agora inbox for [email protected]help / color / mirror / Atom feed
[PATCH v2 1/7] Row pattern recognition patch for raw parser. 2390+ messages / 6 participants [nested] [flat]
* [PATCH v2 1/7] Row pattern recognition patch for raw parser. @ 2023-06-26 08:05 Tatsuo Ishii <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Tatsuo Ishii @ 2023-06-26 08:05 UTC (permalink / raw) --- src/backend/parser/gram.y | 218 +++++++++++++++++++++++++++++--- src/include/nodes/parsenodes.h | 54 ++++++++ src/include/parser/kwlist.h | 8 ++ src/include/parser/parse_node.h | 1 + 4 files changed, 266 insertions(+), 15 deletions(-) diff --git a/src/backend/parser/gram.y b/src/backend/parser/gram.y index 39ab7eac0d..5cd3ebaa98 100644 --- a/src/backend/parser/gram.y +++ b/src/backend/parser/gram.y @@ -251,6 +251,8 @@ static Node *makeRecursiveViewSelect(char *relname, List *aliases, Node *query); DefElem *defelt; SortBy *sortby; WindowDef *windef; + RPCommonSyntax *rpcom; + RPSubsetItem *rpsubset; JoinExpr *jexpr; IndexElem *ielem; StatsElem *selem; @@ -453,8 +455,12 @@ static Node *makeRecursiveViewSelect(char *relname, List *aliases, Node *query); TriggerTransitions TriggerReferencing vacuum_relation_list opt_vacuum_relation_list drop_option_list pub_obj_list - -%type <node> opt_routine_body + row_pattern_measure_list row_pattern_definition_list + opt_row_pattern_subset_clause + row_pattern_subset_list row_pattern_subset_rhs + row_pattern +%type <rpsubset> row_pattern_subset_item +%type <node> opt_routine_body row_pattern_term %type <groupclause> group_clause %type <list> group_by_list %type <node> group_by_item empty_grouping_set rollup_clause cube_clause @@ -551,6 +557,7 @@ static Node *makeRecursiveViewSelect(char *relname, List *aliases, Node *query); %type <range> relation_expr_opt_alias %type <node> tablesample_clause opt_repeatable_clause %type <target> target_el set_target insert_column_item + row_pattern_measure_item row_pattern_definition %type <str> generic_option_name %type <node> generic_option_arg @@ -633,6 +640,9 @@ static Node *makeRecursiveViewSelect(char *relname, List *aliases, Node *query); %type <list> window_clause window_definition_list opt_partition_clause %type <windef> window_definition over_clause window_specification opt_frame_clause frame_extent frame_bound +%type <rpcom> opt_row_pattern_common_syntax opt_row_pattern_skip_to +%type <boolean> opt_row_pattern_initial_or_seek +%type <list> opt_row_pattern_measures %type <ival> opt_window_exclusion_clause %type <str> opt_existing_window_name %type <boolean> opt_if_not_exists @@ -645,7 +655,6 @@ static Node *makeRecursiveViewSelect(char *relname, List *aliases, Node *query); %type <list> hash_partbound %type <defelt> hash_partbound_elem - %type <node> json_format_clause_opt json_value_expr json_output_clause_opt @@ -705,7 +714,7 @@ static Node *makeRecursiveViewSelect(char *relname, List *aliases, Node *query); CURRENT_TIME CURRENT_TIMESTAMP CURRENT_USER CURSOR CYCLE DATA_P DATABASE DAY_P DEALLOCATE DEC DECIMAL_P DECLARE DEFAULT DEFAULTS - DEFERRABLE DEFERRED DEFINER DELETE_P DELIMITER DELIMITERS DEPENDS DEPTH DESC + DEFERRABLE DEFERRED DEFINE DEFINER DELETE_P DELIMITER DELIMITERS DEPENDS DEPTH DESC DETACH DICTIONARY DISABLE_P DISCARD DISTINCT DO DOCUMENT_P DOMAIN_P DOUBLE_P DROP @@ -721,7 +730,7 @@ static Node *makeRecursiveViewSelect(char *relname, List *aliases, Node *query); HANDLER HAVING HEADER_P HOLD HOUR_P IDENTITY_P IF_P ILIKE IMMEDIATE IMMUTABLE IMPLICIT_P IMPORT_P IN_P INCLUDE - INCLUDING INCREMENT INDENT INDEX INDEXES INHERIT INHERITS INITIALLY INLINE_P + INCLUDING INCREMENT INDENT INDEX INDEXES INHERIT INHERITS INITIAL INITIALLY INLINE_P INNER_P INOUT INPUT_P INSENSITIVE INSERT INSTEAD INT_P INTEGER INTERSECT INTERVAL INTO INVOKER IS ISNULL ISOLATION @@ -733,7 +742,7 @@ static Node *makeRecursiveViewSelect(char *relname, List *aliases, Node *query); LEADING LEAKPROOF LEAST LEFT LEVEL LIKE LIMIT LISTEN LOAD LOCAL LOCALTIME LOCALTIMESTAMP LOCATION LOCK_P LOCKED LOGGED - MAPPING MATCH MATCHED MATERIALIZED MAXVALUE MERGE METHOD + MAPPING MATCH MATCHED MATERIALIZED MAXVALUE MEASURES MERGE METHOD MINUTE_P MINVALUE MODE MONTH_P MOVE NAME_P NAMES NATIONAL NATURAL NCHAR NEW NEXT NFC NFD NFKC NFKD NO NONE @@ -745,9 +754,9 @@ static Node *makeRecursiveViewSelect(char *relname, List *aliases, Node *query); ORDER ORDINALITY OTHERS OUT_P OUTER_P OVER OVERLAPS OVERLAY OVERRIDING OWNED OWNER - PARALLEL PARAMETER PARSER PARTIAL PARTITION PASSING PASSWORD - PLACING PLANS POLICY - POSITION PRECEDING PRECISION PRESERVE PREPARE PREPARED PRIMARY + PARALLEL PARAMETER PARSER PARTIAL PARTITION PASSING PASSWORD PAST + PATTERN PLACING PLANS POLICY + POSITION PRECEDING PRECISION PREMUTE PRESERVE PREPARE PREPARED PRIMARY PRIOR PRIVILEGES PROCEDURAL PROCEDURE PROCEDURES PROGRAM PUBLICATION QUOTE @@ -757,12 +766,13 @@ static Node *makeRecursiveViewSelect(char *relname, List *aliases, Node *query); RESET RESTART RESTRICT RETURN RETURNING RETURNS REVOKE RIGHT ROLE ROLLBACK ROLLUP ROUTINE ROUTINES ROW ROWS RULE - SAVEPOINT SCALAR SCHEMA SCHEMAS SCROLL SEARCH SECOND_P SECURITY SELECT + SAVEPOINT SCALAR SCHEMA SCHEMAS SCROLL SEARCH SECOND_P SECURITY SEEK SELECT SEQUENCE SEQUENCES + SERIALIZABLE SERVER SESSION SESSION_USER SET SETS SETOF SHARE SHOW SIMILAR SIMPLE SKIP SMALLINT SNAPSHOT SOME SQL_P STABLE STANDALONE_P START STATEMENT STATISTICS STDIN STDOUT STORAGE STORED STRICT_P STRIP_P - SUBSCRIPTION SUBSTRING SUPPORT SYMMETRIC SYSID SYSTEM_P SYSTEM_USER + SUBSCRIPTION SUBSET SUBSTRING SUPPORT SYMMETRIC SYSID SYSTEM_P SYSTEM_USER TABLE TABLES TABLESAMPLE TABLESPACE TEMP TEMPLATE TEMPORARY TEXT_P THEN TIES TIME TIMESTAMP TO TRAILING TRANSACTION TRANSFORM @@ -855,6 +865,7 @@ static Node *makeRecursiveViewSelect(char *relname, List *aliases, Node *query); */ %nonassoc UNBOUNDED /* ideally would have same precedence as IDENT */ %nonassoc IDENT PARTITION RANGE ROWS GROUPS PRECEDING FOLLOWING CUBE ROLLUP +%nonassoc MEASURES AFTER INITIAL SEEK PATTERN %left Op OPERATOR /* multi-character ops and user-defined operators */ %left '+' '-' %left '*' '/' '%' @@ -15773,7 +15784,8 @@ over_clause: OVER window_specification ; window_specification: '(' opt_existing_window_name opt_partition_clause - opt_sort_clause opt_frame_clause ')' + opt_sort_clause opt_row_pattern_measures opt_frame_clause + opt_row_pattern_common_syntax ')' { WindowDef *n = makeNode(WindowDef); @@ -15781,10 +15793,12 @@ window_specification: '(' opt_existing_window_name opt_partition_clause n->refname = $2; n->partitionClause = $3; n->orderClause = $4; + n->rowPatternMeasures = $5; /* copy relevant fields of opt_frame_clause */ - n->frameOptions = $5->frameOptions; - n->startOffset = $5->startOffset; - n->endOffset = $5->endOffset; + n->frameOptions = $6->frameOptions; + n->startOffset = $6->startOffset; + n->endOffset = $6->endOffset; + n->rpCommonSyntax = $7; n->location = @1; $$ = n; } @@ -15808,6 +15822,31 @@ opt_partition_clause: PARTITION BY expr_list { $$ = $3; } | /*EMPTY*/ { $$ = NIL; } ; +/* + * ROW PATTERN MEASURES + */ +opt_row_pattern_measures: MEASURES row_pattern_measure_list { $$ = $2; } + | /*EMPTY*/ { $$ = NIL; } + ; + +row_pattern_measure_list: + row_pattern_measure_item + { $$ = list_make1($1); } + | row_pattern_measure_list ',' row_pattern_measure_item + { $$ = lappend($1, $3); } + ; + +row_pattern_measure_item: + a_expr AS ColLabel + { + $$ = makeNode(ResTarget); + $$->name = $3; + $$->indirection = NIL; + $$->val = (Node *) $1; + $$->location = @1; + } + ; + /* * For frame clauses, we return a WindowDef, but only some fields are used: * frameOptions, startOffset, and endOffset. @@ -15967,6 +16006,139 @@ opt_window_exclusion_clause: | /*EMPTY*/ { $$ = 0; } ; +opt_row_pattern_common_syntax: +opt_row_pattern_skip_to opt_row_pattern_initial_or_seek + PATTERN '(' row_pattern ')' + opt_row_pattern_subset_clause + DEFINE row_pattern_definition_list + { + RPCommonSyntax *n = makeNode(RPCommonSyntax); + n->rpSkipTo = $1->rpSkipTo; + n->rpSkipVariable = $1->rpSkipVariable; + n->initial = $2; + n->rpPatterns = $5; + n->rpSubsetClause = $7; + n->rpDefs = $9; + $$ = n; + } + | /*EMPTY*/ { $$ = NULL; } + ; + +opt_row_pattern_skip_to: + AFTER MATCH SKIP TO NEXT ROW + { + RPCommonSyntax *n = makeNode(RPCommonSyntax); + n->rpSkipTo = ST_NEXT_ROW; + n->rpSkipVariable = NULL; + $$ = n; + } + | AFTER MATCH SKIP PAST LAST_P ROW + { + RPCommonSyntax *n = makeNode(RPCommonSyntax); + n->rpSkipTo = ST_PAST_LAST_ROW; + n->rpSkipVariable = NULL; + $$ = n; + } +/* + | AFTER MATCH SKIP TO FIRST_P ColId %prec FIRST_P + { + RPCommonSyntax *n = makeNode(RPCommonSyntax); + n->rpSkipTo = ST_FIRST_VARIABLE; + n->rpSkipVariable = $6; + $$ = n; + } + | AFTER MATCH SKIP TO LAST_P ColId %prec LAST_P + { + RPCommonSyntax *n = makeNode(RPCommonSyntax); + n->rpSkipTo = ST_LAST_VARIABLE; + n->rpSkipVariable = $6; + $$ = n; + } + * Shift/reduce + | AFTER MATCH SKIP TO ColId + { + RPCommonSyntax *n = makeNode(RPCommonSyntax); + n->rpSkipTo = ST_VARIABLE; + n->rpSkipVariable = $5; + $$ = n; + } +*/ + | /*EMPTY*/ + { + RPCommonSyntax *n = makeNode(RPCommonSyntax); + /* temporary set default to ST_NEXT_ROW */ + n->rpSkipTo = ST_PAST_LAST_ROW; + n->rpSkipVariable = NULL; + $$ = n; + } + ; + +opt_row_pattern_initial_or_seek: + INITIAL { $$ = true; } + | SEEK + { + ereport(ERROR, + (errcode(ERRCODE_SYNTAX_ERROR), + errmsg("SEEK is not supported"), + errhint("Use INITIAL."), + parser_errposition(@1))); + } + | /*EMPTY*/ { $$ = true; } + ; + +row_pattern: + row_pattern_term { $$ = list_make1($1); } + | row_pattern row_pattern_term { $$ = lappend($1, $2); } + ; + +row_pattern_term: + ColId { $$ = (Node *) makeSimpleA_Expr(AEXPR_OP, "", (Node *)makeString($1), NULL, @1); } + | ColId '*' { $$ = (Node *) makeSimpleA_Expr(AEXPR_OP, "*", (Node *)makeString($1), NULL, @1); } + | ColId '+' { $$ = (Node *) makeSimpleA_Expr(AEXPR_OP, "+", (Node *)makeString($1), NULL, @1); } + | ColId '?' { $$ = (Node *) makeSimpleA_Expr(AEXPR_OP, "?", (Node *)makeString($1), NULL, @1); } + ; + +opt_row_pattern_subset_clause: + SUBSET row_pattern_subset_list { $$ = $2; } + | /*EMPTY*/ { $$ = NIL; } + ; + +row_pattern_subset_list: + row_pattern_subset_item { $$ = list_make1($1); } + | row_pattern_subset_list ',' row_pattern_subset_item { $$ = lappend($1, $3); } + | /*EMPTY*/ { $$ = NIL; } + ; + +row_pattern_subset_item: ColId '=' '(' row_pattern_subset_rhs ')' + { + RPSubsetItem *n = makeNode(RPSubsetItem); + n->name = $1; + n->rhsVariable = $4; + $$ = n; + } + ; + +row_pattern_subset_rhs: + ColId { $$ = list_make1(makeStringConst($1, @1)); } + | row_pattern_subset_rhs ',' ColId { $$ = lappend($1, makeStringConst($3, @1)); } + | /*EMPTY*/ { $$ = NIL; } + ; + +row_pattern_definition_list: + row_pattern_definition { $$ = list_make1($1); } + | row_pattern_definition_list ',' row_pattern_definition { $$ = lappend($1, $3); } + ; + +row_pattern_definition: + ColId AS a_expr + { + $$ = makeNode(ResTarget); + $$->name = $1; + $$->indirection = NIL; + $$->val = (Node *) $3; + $$->location = @1; + } + ; /* * Supporting nonterminals for expressions. @@ -17060,6 +17232,7 @@ unreserved_keyword: | INDEXES | INHERIT | INHERITS + | INITIAL | INLINE_P | INPUT_P | INSENSITIVE @@ -17088,6 +17261,7 @@ unreserved_keyword: | MATCHED | MATERIALIZED | MAXVALUE + | MEASURES | MERGE | METHOD | MINUTE_P @@ -17130,9 +17304,12 @@ unreserved_keyword: | PARTITION | PASSING | PASSWORD + | PAST + | PATTERN | PLANS | POLICY | PRECEDING + | PREMUTE | PREPARE | PREPARED | PRESERVE @@ -17180,6 +17357,7 @@ unreserved_keyword: | SEARCH | SECOND_P | SECURITY + | SEEK | SEQUENCE | SEQUENCES | SERIALIZABLE @@ -17205,6 +17383,7 @@ unreserved_keyword: | STRICT_P | STRIP_P | SUBSCRIPTION + | SUBSET | SUPPORT | SYSID | SYSTEM_P @@ -17389,6 +17568,7 @@ reserved_keyword: | CURRENT_USER | DEFAULT | DEFERRABLE + | DEFINE | DESC | DISTINCT | DO @@ -17551,6 +17731,7 @@ bare_label_keyword: | DEFAULTS | DEFERRABLE | DEFERRED + | DEFINE | DEFINER | DELETE_P | DELIMITER @@ -17626,6 +17807,7 @@ bare_label_keyword: | INDEXES | INHERIT | INHERITS + | INITIAL | INITIALLY | INLINE_P | INNER_P @@ -17673,6 +17855,7 @@ bare_label_keyword: | MATCHED | MATERIALIZED | MAXVALUE + | MEASURES | MERGE | METHOD | MINVALUE @@ -17726,11 +17909,14 @@ bare_label_keyword: | PARTITION | PASSING | PASSWORD + | PAST + | PATTERN | PLACING | PLANS | POLICY | POSITION | PRECEDING + | PREMUTE | PREPARE | PREPARED | PRESERVE @@ -17782,6 +17968,7 @@ bare_label_keyword: | SCROLL | SEARCH | SECURITY + | SEEK | SELECT | SEQUENCE | SEQUENCES @@ -17813,6 +18000,7 @@ bare_label_keyword: | STRICT_P | STRIP_P | SUBSCRIPTION + | SUBSET | SUBSTRING | SUPPORT | SYMMETRIC diff --git a/src/include/nodes/parsenodes.h b/src/include/nodes/parsenodes.h index b3bec90e52..22e1a01a0e 100644 --- a/src/include/nodes/parsenodes.h +++ b/src/include/nodes/parsenodes.h @@ -548,6 +548,44 @@ typedef struct SortBy int location; /* operator location, or -1 if none/unknown */ } SortBy; +/* + * AFTER MATCH row pattern skip to> types in row pattern common syntax + */ +typedef enum RPSkipTo +{ + ST_NONE, /* AFTER MATCH omitted */ + ST_NEXT_ROW, /* SKIP TO NEXT ROW */ + ST_PAST_LAST_ROW, /* SKIP TO PAST LAST ROW */ + ST_FIRST_VARIABLE, /* SKIP TO FIRST variable name */ + ST_LAST_VARIABLE, /* SKIP TO LAST variable name */ + ST_VARIABLE /* SKIP TO variable name */ +} RPSkipTo; + +/* + * Row Pattern SUBSET clause item + */ +typedef struct RPSubsetItem +{ + NodeTag type; + char *name; /* Row Pattern SUBSET clause variable name */ + List *rhsVariable; /* Row Pattern SUBSET rhs variables (list of char *string) */ +} RPSubsetItem; + +/* + * RowPatternCommonSyntax - raw representation of row pattern common syntax + * + */ +typedef struct RPCommonSyntax +{ + NodeTag type; + RPSkipTo rpSkipTo; /* Row Pattern AFTER MATCH SKIP type */ + char *rpSkipVariable; /* Row Pattern Skip To variable name, if any */ + bool initial; /* true if <row pattern initial or seek> is initial */ + List *rpPatterns; /* PATTERN variables (list of A_Expr) */ + List *rpSubsetClause; /* row pattern subset clause (list of RPSubsetItem), if any */ + List *rpDefs; /* row pattern definitions clause (list of ResTarget) */ +} RPCommonSyntax; + /* * WindowDef - raw representation of WINDOW and OVER clauses * @@ -563,6 +601,8 @@ typedef struct WindowDef char *refname; /* referenced window name, if any */ List *partitionClause; /* PARTITION BY expression list */ List *orderClause; /* ORDER BY (list of SortBy) */ + List *rowPatternMeasures; /* row pattern measures (list of ResTarget) */ + RPCommonSyntax *rpCommonSyntax; /* row pattern common syntax */ int frameOptions; /* frame_clause options, see below */ Node *startOffset; /* expression for starting bound, if any */ Node *endOffset; /* expression for ending bound, if any */ @@ -1482,6 +1522,11 @@ typedef struct GroupingSet * the orderClause might or might not be copied (see copiedOrder); the framing * options are never copied, per spec. * + * "defineClause" is Row Pattern Recognition DEFINE clause (list of + * TargetEntry). TargetEntry.resname represents row pattern definition + * variable name. "patternVariable" and "patternRegexp" represents PATTERN + * clause. + * * The information relevant for the query jumbling is the partition clause * type and its bounds. */ @@ -1513,6 +1558,15 @@ typedef struct WindowClause Index winref; /* ID referenced by window functions */ /* did we copy orderClause from refname? */ bool copiedOrder pg_node_attr(query_jumble_ignore); + /* Row Pattern Recognition AFTER MACH SKIP clause */ + RPSkipTo rpSkipTo; /* Row Pattern Skip To type */ + bool initial; /* true if <row pattern initial or seek> is initial */ + /* Row Pattern Recognition DEFINE clause (list of TargetEntry) */ + List *defineClause; + /* Row Pattern Recognition PATTERN variable name (list of String) */ + List *patternVariable; + /* Row Pattern Recognition PATTERN regular expression quantifier ('+' or ''. list of String) */ + List *patternRegexp; } WindowClause; /* diff --git a/src/include/parser/kwlist.h b/src/include/parser/kwlist.h index f5b2e61ca5..12603b311c 100644 --- a/src/include/parser/kwlist.h +++ b/src/include/parser/kwlist.h @@ -128,6 +128,7 @@ PG_KEYWORD("default", DEFAULT, RESERVED_KEYWORD, BARE_LABEL) PG_KEYWORD("defaults", DEFAULTS, UNRESERVED_KEYWORD, BARE_LABEL) PG_KEYWORD("deferrable", DEFERRABLE, RESERVED_KEYWORD, BARE_LABEL) PG_KEYWORD("deferred", DEFERRED, UNRESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("define", DEFINE, RESERVED_KEYWORD, BARE_LABEL) PG_KEYWORD("definer", DEFINER, UNRESERVED_KEYWORD, BARE_LABEL) PG_KEYWORD("delete", DELETE_P, UNRESERVED_KEYWORD, BARE_LABEL) PG_KEYWORD("delimiter", DELIMITER, UNRESERVED_KEYWORD, BARE_LABEL) @@ -212,6 +213,7 @@ PG_KEYWORD("index", INDEX, UNRESERVED_KEYWORD, BARE_LABEL) PG_KEYWORD("indexes", INDEXES, UNRESERVED_KEYWORD, BARE_LABEL) PG_KEYWORD("inherit", INHERIT, UNRESERVED_KEYWORD, BARE_LABEL) PG_KEYWORD("inherits", INHERITS, UNRESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("initial", INITIAL, UNRESERVED_KEYWORD, BARE_LABEL) PG_KEYWORD("initially", INITIALLY, RESERVED_KEYWORD, BARE_LABEL) PG_KEYWORD("inline", INLINE_P, UNRESERVED_KEYWORD, BARE_LABEL) PG_KEYWORD("inner", INNER_P, TYPE_FUNC_NAME_KEYWORD, BARE_LABEL) @@ -263,6 +265,7 @@ PG_KEYWORD("match", MATCH, UNRESERVED_KEYWORD, BARE_LABEL) PG_KEYWORD("matched", MATCHED, UNRESERVED_KEYWORD, BARE_LABEL) PG_KEYWORD("materialized", MATERIALIZED, UNRESERVED_KEYWORD, BARE_LABEL) PG_KEYWORD("maxvalue", MAXVALUE, UNRESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("measures", MEASURES, UNRESERVED_KEYWORD, BARE_LABEL) PG_KEYWORD("merge", MERGE, UNRESERVED_KEYWORD, BARE_LABEL) PG_KEYWORD("method", METHOD, UNRESERVED_KEYWORD, BARE_LABEL) PG_KEYWORD("minute", MINUTE_P, UNRESERVED_KEYWORD, AS_LABEL) @@ -324,12 +327,15 @@ PG_KEYWORD("partial", PARTIAL, UNRESERVED_KEYWORD, BARE_LABEL) PG_KEYWORD("partition", PARTITION, UNRESERVED_KEYWORD, BARE_LABEL) PG_KEYWORD("passing", PASSING, UNRESERVED_KEYWORD, BARE_LABEL) PG_KEYWORD("password", PASSWORD, UNRESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("past", PAST, UNRESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("pattern", PATTERN, UNRESERVED_KEYWORD, BARE_LABEL) PG_KEYWORD("placing", PLACING, RESERVED_KEYWORD, BARE_LABEL) PG_KEYWORD("plans", PLANS, UNRESERVED_KEYWORD, BARE_LABEL) PG_KEYWORD("policy", POLICY, UNRESERVED_KEYWORD, BARE_LABEL) PG_KEYWORD("position", POSITION, COL_NAME_KEYWORD, BARE_LABEL) PG_KEYWORD("preceding", PRECEDING, UNRESERVED_KEYWORD, BARE_LABEL) PG_KEYWORD("precision", PRECISION, COL_NAME_KEYWORD, AS_LABEL) +PG_KEYWORD("premute", PREMUTE, UNRESERVED_KEYWORD, BARE_LABEL) PG_KEYWORD("prepare", PREPARE, UNRESERVED_KEYWORD, BARE_LABEL) PG_KEYWORD("prepared", PREPARED, UNRESERVED_KEYWORD, BARE_LABEL) PG_KEYWORD("preserve", PRESERVE, UNRESERVED_KEYWORD, BARE_LABEL) @@ -383,6 +389,7 @@ PG_KEYWORD("scroll", SCROLL, UNRESERVED_KEYWORD, BARE_LABEL) PG_KEYWORD("search", SEARCH, UNRESERVED_KEYWORD, BARE_LABEL) PG_KEYWORD("second", SECOND_P, UNRESERVED_KEYWORD, AS_LABEL) PG_KEYWORD("security", SECURITY, UNRESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("seek", SEEK, UNRESERVED_KEYWORD, BARE_LABEL) PG_KEYWORD("select", SELECT, RESERVED_KEYWORD, BARE_LABEL) PG_KEYWORD("sequence", SEQUENCE, UNRESERVED_KEYWORD, BARE_LABEL) PG_KEYWORD("sequences", SEQUENCES, UNRESERVED_KEYWORD, BARE_LABEL) @@ -414,6 +421,7 @@ PG_KEYWORD("stored", STORED, UNRESERVED_KEYWORD, BARE_LABEL) PG_KEYWORD("strict", STRICT_P, UNRESERVED_KEYWORD, BARE_LABEL) PG_KEYWORD("strip", STRIP_P, UNRESERVED_KEYWORD, BARE_LABEL) PG_KEYWORD("subscription", SUBSCRIPTION, UNRESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("subset", SUBSET, UNRESERVED_KEYWORD, BARE_LABEL) PG_KEYWORD("substring", SUBSTRING, COL_NAME_KEYWORD, BARE_LABEL) PG_KEYWORD("support", SUPPORT, UNRESERVED_KEYWORD, BARE_LABEL) PG_KEYWORD("symmetric", SYMMETRIC, RESERVED_KEYWORD, BARE_LABEL) diff --git a/src/include/parser/parse_node.h b/src/include/parser/parse_node.h index f589112d5e..6640090910 100644 --- a/src/include/parser/parse_node.h +++ b/src/include/parser/parse_node.h @@ -51,6 +51,7 @@ typedef enum ParseExprKind EXPR_KIND_WINDOW_FRAME_RANGE, /* window frame clause with RANGE */ EXPR_KIND_WINDOW_FRAME_ROWS, /* window frame clause with ROWS */ EXPR_KIND_WINDOW_FRAME_GROUPS, /* window frame clause with GROUPS */ + EXPR_KIND_RPR_DEFINE, /* DEFINE */ EXPR_KIND_SELECT_TARGET, /* SELECT target list item */ EXPR_KIND_INSERT_TARGET, /* INSERT target list item */ EXPR_KIND_UPDATE_SOURCE, /* UPDATE assignment source item */ -- 2.25.1 ----Next_Part(Mon_Jun_26_17_45_07_2023_724)-- Content-Type: Text/X-Patch; charset=us-ascii Content-Transfer-Encoding: 7bit Content-Disposition: inline; filename="v2-0002-Row-pattern-recognition-patch-parse-analysis.patch" ^ permalink raw reply [nested|flat] 2390+ messages in thread
* Some shared memory chunks are allocated even if related processes won't start @ 2024-03-04 05:26 Hayato Kuroda (Fujitsu) <[email protected]> 0 siblings, 2 replies; 2390+ messages in thread From: Hayato Kuroda (Fujitsu) @ 2024-03-04 05:26 UTC (permalink / raw) To: '[email protected]' <[email protected]> Dear hackers, While reading codes, I found that ApplyLauncherShmemInit() and AutoVacuumShmemInit() are always called even if they would not be launched. It may be able to reduce the start time to avoid the unnecessary allocation. However, I know this improvement would be quite small because the allocated chunks are quite small. Anyway, there are several ways to fix: 1) Skip calling ShmemInitStruct() if the related process would not be launched. I think this approach is the easiest way. E.g., ``` --- a/src/backend/replication/logical/launcher.c +++ b/src/backend/replication/logical/launcher.c @@ -962,6 +962,9 @@ ApplyLauncherShmemInit(void) { bool found; + if (max_logical_replication_workers == 0 || IsBinaryUpgrade) + return; + ``` 2) Dynamically allocate the shared memory. This was allowed by recent commit [1]. I made a small PoC only for logical launcher to show what I meant. PSA diff file. Since some processes (backend, apply worker, parallel apply worker, and tablesync worker) refers the chunk, codes for attachment must be added on the several places. If you agree it should be fixed, I will create a patch. Thought? [1]: https://github.com/postgres/postgres/commit/8b2bcf3f287c79eaebf724cba57e5ff664b01e06 Best Regards, Hayato Kuroda FUJITSU LIMITED https://www.fujitsu.com/ Attachments: [application/octet-stream] dynamic_allocation.diff (84B, ../../TYCPR01MB12077BFDFBC142086D424FDFEF5232@TYCPR01MB12077.jpnprd01.prod.outlook.com/2-dynamic_allocation.diff) download | inline diff: 53 22 src/backend/replication/logical/launcher.c 0 1 src/backend/storage/ipc/ipci.c ^ permalink raw reply [nested|flat] 2390+ messages in thread
* Re: Some shared memory chunks are allocated even if related processes won't start @ 2024-03-04 05:33 Tom Lane <[email protected]> parent: Hayato Kuroda (Fujitsu) <[email protected]> 1 sibling, 1 reply; 2390+ messages in thread From: Tom Lane @ 2024-03-04 05:33 UTC (permalink / raw) To: Hayato Kuroda (Fujitsu) <[email protected]>; +Cc: '[email protected]' <[email protected]> "Hayato Kuroda (Fujitsu)" <[email protected]> writes: > While reading codes, I found that ApplyLauncherShmemInit() and AutoVacuumShmemInit() > are always called even if they would not be launched. > It may be able to reduce the start time to avoid the unnecessary allocation. Why would this be a good idea? It would require preventing the decision not to launch them from being changed later, except via postmaster restart. We've generally been trying to move away from unchangeable-without-restart decisions. In your example, > + if (max_logical_replication_workers == 0 || IsBinaryUpgrade) > + return; max_logical_replication_workers is already PGC_POSTMASTER so there's not any immediate loss of flexibility, but I don't think it's a great idea to introduce another reason why it has to be PGC_POSTMASTER. regards, tom lane ^ permalink raw reply [nested|flat] 2390+ messages in thread
* RE: Some shared memory chunks are allocated even if related processes won't start @ 2024-03-04 06:10 Hayato Kuroda (Fujitsu) <[email protected]> parent: Tom Lane <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Hayato Kuroda (Fujitsu) @ 2024-03-04 06:10 UTC (permalink / raw) To: 'Tom Lane' <[email protected]>; +Cc: '[email protected]' <[email protected]> Dear Tom, Thanks for replying! > "Hayato Kuroda (Fujitsu)" <[email protected]> writes: > > While reading codes, I found that ApplyLauncherShmemInit() and > AutoVacuumShmemInit() > > are always called even if they would not be launched. > > It may be able to reduce the start time to avoid the unnecessary allocation. > > Why would this be a good idea? It would require preventing the > decision not to launch them from being changed later, except via > postmaster restart. Right. It is important to relax their GucContext. > We've generally been trying to move away > from unchangeable-without-restart decisions. In your example, > > > + if (max_logical_replication_workers == 0 || IsBinaryUpgrade) > > + return; > > max_logical_replication_workers is already PGC_POSTMASTER so there's > not any immediate loss of flexibility, but I don't think it's a great > idea to introduce another reason why it has to be PGC_POSTMASTER. You are right. The first example implied the max_logical_replication_workers won't be changed. So it is not appropriate. So ... what about second one? The approach allows to allocate a memory after startup, which means that users may able to change the parameter from 0 to natural number in future. (Of course, such an operation is prohibit for now). Can it be an initial step to ease the condition? Best Regards, Hayato Kuroda FUJITSU LIMITED https://www.fujitsu.com/ ^ permalink raw reply [nested|flat] 2390+ messages in thread
* Re: Some shared memory chunks are allocated even if related processes won't start @ 2024-03-04 08:09 Alvaro Herrera <[email protected]> parent: Hayato Kuroda (Fujitsu) <[email protected]> 1 sibling, 1 reply; 2390+ messages in thread From: Alvaro Herrera @ 2024-03-04 08:09 UTC (permalink / raw) To: Hayato Kuroda (Fujitsu) <[email protected]>; +Cc: '[email protected]' <[email protected]> On 2024-Mar-04, Hayato Kuroda (Fujitsu) wrote: > Dear hackers, > > While reading codes, I found that ApplyLauncherShmemInit() and > AutoVacuumShmemInit() are always called even if they would not be > launched. Note that there are situations where the autovacuum launcher is started even though autovacuum is nominally turned off, and I suspect your proposal would break that. IIRC this occurs when the Xid or multixact counters cross the max_freeze_age threshold. -- Álvaro Herrera PostgreSQL Developer — https://www.EnterpriseDB.com/ "Porque Kim no hacía nada, pero, eso sí, con extraordinario éxito" ("Kim", Kipling) ^ permalink raw reply [nested|flat] 2390+ messages in thread
* RE: Some shared memory chunks are allocated even if related processes won't start @ 2024-03-04 09:50 Hayato Kuroda (Fujitsu) <[email protected]> parent: Alvaro Herrera <[email protected]> 0 siblings, 1 reply; 2390+ messages in thread From: Hayato Kuroda (Fujitsu) @ 2024-03-04 09:50 UTC (permalink / raw) To: 'Alvaro Herrera' <[email protected]>; +Cc: '[email protected]' <[email protected]> Dear Alvaro, Thanks for giving comments! > > While reading codes, I found that ApplyLauncherShmemInit() and > > AutoVacuumShmemInit() are always called even if they would not be > > launched. > > Note that there are situations where the autovacuum launcher is started > even though autovacuum is nominally turned off, and I suspect your > proposal would break that. IIRC this occurs when the Xid or multixact > counters cross the max_freeze_age threshold. Right. In GetNewTransactionId(), SetTransactionIdLimit() and some other places, PMSIGNAL_START_AUTOVAC_LAUNCHER is sent to postmaster when the xid exceeds autovacuum_freeze_max_age. This work has already been written in the doc [1]: ``` To ensure that this does not happen, autovacuum is invoked on any table that might contain unfrozen rows with XIDs older than the age specified by the configuration parameter autovacuum_freeze_max_age. (This will happen even if autovacuum is disabled.) ``` This means that my first idea won't work well. Even if the postmaster does not initially allocate shared memory, backends may request to start auto vacuum and use the region. However, the second idea is still valid, which allows the allocation of shared memory dynamically. This is a bit efficient for the system which tuples won't be frozen. Thought? [1]: https://www.postgresql.org/docs/devel/routine-vacuuming.html#VACUUM-FOR-WRAPAROUND Best Regards, Hayato Kuroda FUJITSU LIMITED https://www.fujitsu.com/ ^ permalink raw reply [nested|flat] 2390+ messages in thread
* Re: Some shared memory chunks are allocated even if related processes won't start @ 2024-03-04 11:52 'Alvaro Herrera' <[email protected]> parent: Hayato Kuroda (Fujitsu) <[email protected]> 0 siblings, 1 reply; 2390+ messages in thread From: 'Alvaro Herrera' @ 2024-03-04 11:52 UTC (permalink / raw) To: Hayato Kuroda (Fujitsu) <[email protected]>; +Cc: '[email protected]' <[email protected]> On 2024-Mar-04, Hayato Kuroda (Fujitsu) wrote: > However, the second idea is still valid, which allows the allocation > of shared memory dynamically. This is a bit efficient for the system > which tuples won't be frozen. Thought? I think it would be worth allocating AutoVacuumShmem->av_workItems using dynamic shmem allocation, particularly to prevent workitems from being discarded just because the array is full¹; but other than that, the struct is just 64 bytes long so I doubt it's useful to allocate it dynamically. ¹ I mean, if the array is full, just allocate another array, point to it from the original one, and keep going. -- Álvaro Herrera PostgreSQL Developer — https://www.EnterpriseDB.com/ "The problem with the facetime model is not just that it's demoralizing, but that the people pretending to work interrupt the ones actually working." -- Paul Graham, http://www.paulgraham.com/opensource.html ^ permalink raw reply [nested|flat] 2390+ messages in thread
* RE: Some shared memory chunks are allocated even if related processes won't start @ 2024-03-04 13:11 Hayato Kuroda (Fujitsu) <[email protected]> parent: 'Alvaro Herrera' <[email protected]> 0 siblings, 1 reply; 2390+ messages in thread From: Hayato Kuroda (Fujitsu) @ 2024-03-04 13:11 UTC (permalink / raw) To: 'Alvaro Herrera' <[email protected]>; +Cc: '[email protected]' <[email protected]> Dear Alvaro, Thanks for discussing! > > I think it would be worth allocating AutoVacuumShmem->av_workItems using > dynamic shmem allocation, particularly to prevent workitems from being > discarded just because the array is full¹; but other than that, the > struct is just 64 bytes long so I doubt it's useful to allocate it > dynamically. > > ¹ I mean, if the array is full, just allocate another array, point to it > from the original one, and keep going. OK, I understood that my initial proposal is not so valuable, so I can withdraw it. About the suggetion, you imagined AutoVacuumRequestWork() and brininsert(), right? I agreed it sounds good, but I don't think it can be implemented by current interface. An interface for dynamically allocating memory is GetNamedDSMSegment(), and it returns the same shared memory region if input names are the same. Therefore, there is no way to re-alloc the shared memory. Best Regards, Hayato Kuroda FUJITSU LIMITED https://www.fujitsu.com/ ^ permalink raw reply [nested|flat] 2390+ messages in thread
* Re: Some shared memory chunks are allocated even if related processes won't start @ 2024-03-04 13:50 'Alvaro Herrera' <[email protected]> parent: Hayato Kuroda (Fujitsu) <[email protected]> 0 siblings, 1 reply; 2390+ messages in thread From: 'Alvaro Herrera' @ 2024-03-04 13:50 UTC (permalink / raw) To: Hayato Kuroda (Fujitsu) <[email protected]>; +Cc: '[email protected]' <[email protected]> Hello Hayato, On 2024-Mar-04, Hayato Kuroda (Fujitsu) wrote: > OK, I understood that my initial proposal is not so valuable, so I can > withdraw it. Yeah, that's what it seems to me. > About the suggetion, you imagined AutoVacuumRequestWork() and > brininsert(), right? Correct. > I agreed it sounds good, but I don't think it can be implemented by > current interface. An interface for dynamically allocating memory is > GetNamedDSMSegment(), and it returns the same shared memory region if > input names are the same. Therefore, there is no way to re-alloc the > shared memory. Yeah, I was imagining something like this: the workitem-array becomes a struct, which has a name and a "next" pointer and a variable number of workitem slots; the AutoVacuumShmem struct has a pointer to the first workitem-struct and the last one; when a workitem is requested by brininsert, we initially allocate via GetNamedDSMSegment("workitem-0") a workitem-struct with a smallish number of elements; if we request another workitem and the array is full, we allocate another array via GetNamedDSMSegment("workitem-1") and store a pointer to it in workitem-0 (so that the list can be followed by an autovacuum worker that's processing the database), and it's also set as the tail of the list in AutoVacuumShmem (so that we know where to store further work items). When all items in a workitem-struct are processed, we can free it (I guess via dsm_unpin_segment), and make AutoVacuumShmem->av_workitems point to the next one in the list. This way, the "array" can grow arbitrarily. -- Álvaro Herrera PostgreSQL Developer — https://www.EnterpriseDB.com/ ^ permalink raw reply [nested|flat] 2390+ messages in thread
* RE: Some shared memory chunks are allocated even if related processes won't start @ 2024-03-05 02:00 Hayato Kuroda (Fujitsu) <[email protected]> parent: 'Alvaro Herrera' <[email protected]> 0 siblings, 1 reply; 2390+ messages in thread From: Hayato Kuroda (Fujitsu) @ 2024-03-05 02:00 UTC (permalink / raw) To: 'Alvaro Herrera' <[email protected]>; +Cc: '[email protected]' <[email protected]> Dear Alvaro, Thanks for giving comments! > > I agreed it sounds good, but I don't think it can be implemented by > > current interface. An interface for dynamically allocating memory is > > GetNamedDSMSegment(), and it returns the same shared memory region if > > input names are the same. Therefore, there is no way to re-alloc the > > shared memory. > > Yeah, I was imagining something like this: the workitem-array becomes a > struct, which has a name and a "next" pointer and a variable number of > workitem slots; the AutoVacuumShmem struct has a pointer to the first > workitem-struct and the last one; when a workitem is requested by > brininsert, we initially allocate via GetNamedDSMSegment("workitem-0") a > workitem-struct with a smallish number of elements; if we request > another workitem and the array is full, we allocate another array via > GetNamedDSMSegment("workitem-1") and store a pointer to it in workitem-0 > (so that the list can be followed by an autovacuum worker that's > processing the database), and it's also set as the tail of the list in > AutoVacuumShmem (so that we know where to store further work items). > When all items in a workitem-struct are processed, we can free it > (I guess via dsm_unpin_segment), and make AutoVacuumShmem->av_workitems > point to the next one in the list. > > This way, the "array" can grow arbitrarily. > Basically sounds good. My concerns are: * GetNamedDSMSegment() does not returns a raw pointer to dsm_segment. This means that it may be difficult to do dsm_unpin_segment on the caller side. * dynamic shared memory is recorded in dhash (dsm_registry_table) and the entry won't be deleted. The reference for the chunk might be remained. Overall, it may be needed that dsm_registry may be also extended. I do not start working yet, so will share results after trying them. Best Regards, Hayato Kuroda FUJITSU LIMITED https://www.fujitsu.com/ ^ permalink raw reply [nested|flat] 2390+ messages in thread
* Re: Some shared memory chunks are allocated even if related processes won't start @ 2024-03-05 07:34 'Alvaro Herrera' <[email protected]> parent: Hayato Kuroda (Fujitsu) <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: 'Alvaro Herrera' @ 2024-03-05 07:34 UTC (permalink / raw) To: Hayato Kuroda (Fujitsu) <[email protected]>; +Cc: [email protected] On 2024-Mar-05, Hayato Kuroda (Fujitsu) wrote: > Basically sounds good. My concerns are: > > * GetNamedDSMSegment() does not returns a raw pointer to dsm_segment. This means > that it may be difficult to do dsm_unpin_segment on the caller side. Maybe we don't need a "named" DSM segment at all, and instead just use bare dsm segments (dsm_create and friends) or a DSA -- not sure. But see commit 31ae1638ce35, which removed use of a DSA in autovacuum/BRIN. Maybe fixing this is just a matter of reverting that commit. At the time, there was a belief that DSA wasn't supported everywhere so we couldn't use it for autovacuum workitem stuff, but I think our reliance on DSA is now past the critical point. BTW, we should turn BRIN autosummarization to be on by default. -- Álvaro Herrera PostgreSQL Developer — https://www.EnterpriseDB.com/ "Las mujeres son como hondas: mientras más resistencia tienen, más lejos puedes llegar con ellas" (Jonas Nightingale, Leap of Faith) ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v3] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-23 09:27 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-23 09:27 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing them to hit the default case and error out with "unsupported object class". During DROP PROPERTY GRAPH, this manifests when an event trigger is active, because pg_event_trigger_ddl_commands() calls these functions. The same code paths are also reachable via pg_identify_object() and pg_identify_object_as_address(). This commit adds the missing cases. Test coverage is added in object_address.sql for these two catalog types and in create_property_graph.sql covering all property graph object types. A test in event_trigger.sql verifies that DROP PROPERTY GRAPH works correctly when an event trigger is active. Author: Bertrand Drouvot <[email protected]> Reviewed-by: Michael Paquier <[email protected]> Reviewed-by: Ashutosh Bapat <[email protected]> Discussion: https://postgr.es/m/aej1DkLwhyZWmtxJ@bdtpg --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 78 ++++++++++++++++ src/test/regress/expected/event_trigger.out | 17 ++++ src/test/regress/expected/object_address.out | 10 +- .../regress/sql/create_property_graph.sql | 23 +++++ src/test/regress/sql/event_trigger.sql | 13 +++ src/test/regress/sql/object_address.sql | 6 +- 7 files changed, 238 insertions(+), 2 deletions(-) 14.7% src/backend/catalog/ 75.5% src/test/regress/expected/ 9.7% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..eb9e17fb727 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -752,6 +752,84 @@ SELECT (pg_identify_object(classid, objid, objsubid)).* type | create_property_graph_tests | g2 | create_property_graph_tests.g2 (21 rows) +-- test object address functions with recursive dependency walk +-- covers all property graph object types including indirect dependents +SELECT * +FROM ( + WITH RECURSIVE deps (classid, objid, objsubid, refclassid, refobjid, refobjsubid) AS ( + SELECT classid, objid, objsubid, + refclassid, refobjid, refobjsubid + FROM pg_depend + WHERE refclassid = 'pg_class'::regclass AND + refobjid = 'create_property_graph_tests.gt'::regclass + UNION ALL + SELECT d.classid, d.objid, d.objsubid, + d.refclassid, d.refobjid, d.refobjsubid + FROM pg_depend d + JOIN deps dp ON d.refclassid = dp.classid AND d.refobjid = dp.objid AND d.refobjsubid = dp.objsubid + ) + SELECT pg_describe_object(classid, objid, objsubid) as obj, + pg_identify_object(classid, objid, objsubid) as ident, + pg_identify_object_as_address(classid, objid, objsubid) as addr + FROM deps +) s +ORDER BY obj COLLATE "C", ident::text COLLATE "C"; + obj | ident | addr +----------------------------------------------------------+----------------------------------------------------------------------------+---------------------------------------------------------------------------- + edge e of property graph gt | ("property graph element",,,"e of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,e}",{}) + edge e of property graph gt | ("property graph element",,,"e of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,e}",{}) + edge e of property graph gt | ("property graph element",,,"e of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of property graph gt | ("property graph label",,,"e of create_property_graph_tests.gt") | ("property graph label","{create_property_graph_tests,gt,e}",{}) + label v1 of property graph gt | ("property graph label",,,"v1 of create_property_graph_tests.gt") | ("property graph label","{create_property_graph_tests,gt,v1}",{}) + label v1 of vertex v1 of property graph gt | ("property graph element label",,,"v1 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v1}",{}) + label v1 of vertex v1 of property graph gt | ("property graph element label",,,"v1 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v1}",{}) + label v2 of property graph gt | ("property graph label",,,"v2 of create_property_graph_tests.gt") | ("property graph label","{create_property_graph_tests,gt,v2}",{}) + label v2 of vertex v2 of property graph gt | ("property graph element label",,,"v2 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v2}",{}) + label v2 of vertex v2 of property graph gt | ("property graph element label",,,"v2 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v2}",{}) + property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property a of property graph gt | ("property graph property",,,"a of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,a}",{}) + property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property b of property graph gt | ("property graph property",,,"b of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,b}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of property graph gt | ("property graph property",,,"c of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,c}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of property graph gt | ("property graph property",,,"k1 of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,k1}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of property graph gt | ("property graph property",,,"k2 of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,k2}",{}) + property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property m of property graph gt | ("property graph property",,,"m of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,m}",{}) + property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property n of property graph gt | ("property graph property",,,"n of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,n}",{}) + type gt | (type,create_property_graph_tests,gt,create_property_graph_tests.gt) | (type,{create_property_graph_tests.gt},{}) + type gt[] | (type,create_property_graph_tests,_gt,create_property_graph_tests.gt[]) | (type,{create_property_graph_tests.gt[]},{}) + vertex v1 of property graph gt | ("property graph element",,,"v1 of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,v1}",{}) + vertex v2 of property graph gt | ("property graph element",,,"v2 of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,v2}",{}) +(52 rows) + \a\t SELECT pg_get_propgraphdef('g2'::regclass); CREATE PROPERTY GRAPH create_property_graph_tests.g2 diff --git a/src/test/regress/expected/event_trigger.out b/src/test/regress/expected/event_trigger.out index 065f586310f..ed8d5df397e 100644 --- a/src/test/regress/expected/event_trigger.out +++ b/src/test/regress/expected/event_trigger.out @@ -173,6 +173,23 @@ NOTICE: test_event_trigger: ddl_command_end CREATE USER MAPPING alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; NOTICE: test_event_trigger: ddl_command_end ALTER DEFAULT PRIVILEGES +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE TABLE t2x (i int PRIMARY KEY, j text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); +NOTICE: test_event_trigger: ddl_command_end CREATE PROPERTY GRAPH +DROP PROPERTY GRAPH gx; +NOTICE: test_event_trigger: ddl_command_end DROP PROPERTY GRAPH +DROP TABLE t1x, t2x; +NOTICE: test_event_trigger: ddl_command_end DROP TABLE -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; ERROR: permission denied to change owner of event trigger "regress_event_trigger" diff --git a/src/test/regress/expected/object_address.out b/src/test/regress/expected/object_address.out index 97227d67a54..5e53f0b092e 100644 --- a/src/test/regress/expected/object_address.out +++ b/src/test/regress/expected/object_address.out @@ -67,7 +67,9 @@ DECLARE BEGIN FOR objtype IN VALUES ('toast table'), ('index column'), ('sequence column'), ('toast table column'), ('view column'), ('materialized view column'), - ('property graph element'), ('property graph label'), ('property graph property') + ('property graph element'), ('property graph element label'), + ('property graph label'), ('property graph label property'), + ('property graph property') LOOP BEGIN PERFORM pg_get_object_address(objtype, '{one}', '{}'); @@ -84,7 +86,9 @@ WARNING: error for toast table column: unsupported object type "toast table col WARNING: error for view column: unsupported object type "view column" WARNING: error for materialized view column: unsupported object type "materialized view column" WARNING: error for property graph element: unsupported object type "property graph element" +WARNING: error for property graph element label: unrecognized object type "property graph element label" WARNING: error for property graph label: unsupported object type "property graph label" +WARNING: error for property graph label property: unrecognized object type "property graph label property" WARNING: error for property graph property: unsupported object type "property graph property" -- miscellaneous other errors select * from pg_get_object_address('operator of access method', '{btree,integer_ops,1}', '{int4,bool}'); @@ -593,7 +597,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace @@ -653,6 +659,8 @@ ORDER BY objects.classid, objects.objid, objects.objsubid; ("(""parameter ACL"",,,)")|("(""parameter ACL"",,)")|NULL ("(""property graph element"",,,)")|("(""property graph element"",,)")|NULL ("(""property graph label"",,,)")|("(""property graph label"",,)")|NULL +("(""property graph element label"",,,)")|("(""property graph element label"",,)")|NULL ("(""property graph property"",,,)")|("(""property graph property"",,)")|NULL +("(""property graph label property"",,,)")|("(""property graph label property"",,)")|NULL -- restore normal output mode \a\t diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..9608dd5c4af 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -298,6 +298,29 @@ SELECT (pg_identify_object(classid, objid, objsubid)).* refobjid = 'create_property_graph_tests.g2'::regclass ORDER BY 1, 2, 3, 4; +-- test object address functions with recursive dependency walk +-- covers all property graph object types including indirect dependents +SELECT * +FROM ( + WITH RECURSIVE deps (classid, objid, objsubid, refclassid, refobjid, refobjsubid) AS ( + SELECT classid, objid, objsubid, + refclassid, refobjid, refobjsubid + FROM pg_depend + WHERE refclassid = 'pg_class'::regclass AND + refobjid = 'create_property_graph_tests.gt'::regclass + UNION ALL + SELECT d.classid, d.objid, d.objsubid, + d.refclassid, d.refobjid, d.refobjsubid + FROM pg_depend d + JOIN deps dp ON d.refclassid = dp.classid AND d.refobjid = dp.objid AND d.refobjsubid = dp.objsubid + ) + SELECT pg_describe_object(classid, objid, objsubid) as obj, + pg_identify_object(classid, objid, objsubid) as ident, + pg_identify_object_as_address(classid, objid, objsubid) as addr + FROM deps +) s +ORDER BY obj COLLATE "C", ident::text COLLATE "C"; + \a\t SELECT pg_get_propgraphdef('g2'::regclass); SELECT pg_get_propgraphdef('g3'::regclass); diff --git a/src/test/regress/sql/event_trigger.sql b/src/test/regress/sql/event_trigger.sql index 32e9bb58c5e..271f443378b 100644 --- a/src/test/regress/sql/event_trigger.sql +++ b/src/test/regress/sql/event_trigger.sql @@ -143,6 +143,19 @@ create user mapping for regress_evt_user server useless_server; alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +CREATE TABLE t2x (i int PRIMARY KEY, j text); + +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); + +DROP PROPERTY GRAPH gx; +DROP TABLE t1x, t2x; + -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; diff --git a/src/test/regress/sql/object_address.sql b/src/test/regress/sql/object_address.sql index 1bbe9457c1c..27109d421c7 100644 --- a/src/test/regress/sql/object_address.sql +++ b/src/test/regress/sql/object_address.sql @@ -67,7 +67,9 @@ DECLARE BEGIN FOR objtype IN VALUES ('toast table'), ('index column'), ('sequence column'), ('toast table column'), ('view column'), ('materialized view column'), - ('property graph element'), ('property graph label'), ('property graph property') + ('property graph element'), ('property graph element label'), + ('property graph label'), ('property graph label property'), + ('property graph property') LOOP BEGIN PERFORM pg_get_object_address(objtype, '{one}', '{}'); @@ -282,7 +284,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace -- 2.34.1 --R84XrR4Hgw0dH3Ec-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v2] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-23 09:27 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-23 09:27 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing them to hit the default case and error out with "unsupported object class". During DROP PROPERTY GRAPH, this manifests when an event trigger is active, because pg_event_trigger_ddl_commands() calls these functions. The same code paths are also reachable via pg_identify_object() and pg_identify_object_as_address(). This commit adds the missing cases. Test coverage is added in object_address.sql for these two catalog types via the zero-OID test that exercises pg_identify_object() and pg_identify_object_as_address(). A test in event_trigger.sql verifies that DROP PROPERTY GRAPH works correctly when an event trigger is active. Author: Bertrand Drouvot <[email protected]> Reviewed-by: Michael Paquier <[email protected]> Reviewed-by: Ashutosh Bapat <[email protected]> Discussion: https://postgr.es/m/aej1DkLwhyZWmtxJ@bdtpg --- src/backend/catalog/objectaddress.c | 93 ++++++++++++++++++++ src/test/regress/expected/event_trigger.out | 17 ++++ src/test/regress/expected/object_address.out | 4 + src/test/regress/sql/event_trigger.sql | 13 +++ src/test/regress/sql/object_address.sql | 2 + 5 files changed, 129 insertions(+) 62.4% src/backend/catalog/ 25.6% src/test/regress/expected/ 11.8% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/event_trigger.out b/src/test/regress/expected/event_trigger.out index 065f586310f..ed8d5df397e 100644 --- a/src/test/regress/expected/event_trigger.out +++ b/src/test/regress/expected/event_trigger.out @@ -173,6 +173,23 @@ NOTICE: test_event_trigger: ddl_command_end CREATE USER MAPPING alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; NOTICE: test_event_trigger: ddl_command_end ALTER DEFAULT PRIVILEGES +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE TABLE t2x (i int PRIMARY KEY, j text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); +NOTICE: test_event_trigger: ddl_command_end CREATE PROPERTY GRAPH +DROP PROPERTY GRAPH gx; +NOTICE: test_event_trigger: ddl_command_end DROP PROPERTY GRAPH +DROP TABLE t1x, t2x; +NOTICE: test_event_trigger: ddl_command_end DROP TABLE -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; ERROR: permission denied to change owner of event trigger "regress_event_trigger" diff --git a/src/test/regress/expected/object_address.out b/src/test/regress/expected/object_address.out index 97227d67a54..729c3537f25 100644 --- a/src/test/regress/expected/object_address.out +++ b/src/test/regress/expected/object_address.out @@ -593,7 +593,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace @@ -653,6 +655,8 @@ ORDER BY objects.classid, objects.objid, objects.objsubid; ("(""parameter ACL"",,,)")|("(""parameter ACL"",,)")|NULL ("(""property graph element"",,,)")|("(""property graph element"",,)")|NULL ("(""property graph label"",,,)")|("(""property graph label"",,)")|NULL +("(""property graph element label"",,,)")|("(""property graph element label"",,)")|NULL ("(""property graph property"",,,)")|("(""property graph property"",,)")|NULL +("(""property graph label property"",,,)")|("(""property graph label property"",,)")|NULL -- restore normal output mode \a\t diff --git a/src/test/regress/sql/event_trigger.sql b/src/test/regress/sql/event_trigger.sql index 32e9bb58c5e..271f443378b 100644 --- a/src/test/regress/sql/event_trigger.sql +++ b/src/test/regress/sql/event_trigger.sql @@ -143,6 +143,19 @@ create user mapping for regress_evt_user server useless_server; alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +CREATE TABLE t2x (i int PRIMARY KEY, j text); + +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); + +DROP PROPERTY GRAPH gx; +DROP TABLE t1x, t2x; + -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; diff --git a/src/test/regress/sql/object_address.sql b/src/test/regress/sql/object_address.sql index 1bbe9457c1c..620dacf1045 100644 --- a/src/test/regress/sql/object_address.sql +++ b/src/test/regress/sql/object_address.sql @@ -282,7 +282,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace -- 2.34.1 --gtUR827Uq8d5gVsQ-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v3] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-23 09:27 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-23 09:27 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing them to hit the default case and error out with "unsupported object class". During DROP PROPERTY GRAPH, this manifests when an event trigger is active, because pg_event_trigger_ddl_commands() calls these functions. The same code paths are also reachable via pg_identify_object() and pg_identify_object_as_address(). This commit adds the missing cases. Test coverage is added in object_address.sql for these two catalog types and in create_property_graph.sql covering all property graph object types. A test in event_trigger.sql verifies that DROP PROPERTY GRAPH works correctly when an event trigger is active. Author: Bertrand Drouvot <[email protected]> Reviewed-by: Michael Paquier <[email protected]> Reviewed-by: Ashutosh Bapat <[email protected]> Discussion: https://postgr.es/m/aej1DkLwhyZWmtxJ@bdtpg --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 78 ++++++++++++++++ src/test/regress/expected/event_trigger.out | 17 ++++ src/test/regress/expected/object_address.out | 10 +- .../regress/sql/create_property_graph.sql | 23 +++++ src/test/regress/sql/event_trigger.sql | 13 +++ src/test/regress/sql/object_address.sql | 6 +- 7 files changed, 238 insertions(+), 2 deletions(-) 14.7% src/backend/catalog/ 75.5% src/test/regress/expected/ 9.7% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..eb9e17fb727 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -752,6 +752,84 @@ SELECT (pg_identify_object(classid, objid, objsubid)).* type | create_property_graph_tests | g2 | create_property_graph_tests.g2 (21 rows) +-- test object address functions with recursive dependency walk +-- covers all property graph object types including indirect dependents +SELECT * +FROM ( + WITH RECURSIVE deps (classid, objid, objsubid, refclassid, refobjid, refobjsubid) AS ( + SELECT classid, objid, objsubid, + refclassid, refobjid, refobjsubid + FROM pg_depend + WHERE refclassid = 'pg_class'::regclass AND + refobjid = 'create_property_graph_tests.gt'::regclass + UNION ALL + SELECT d.classid, d.objid, d.objsubid, + d.refclassid, d.refobjid, d.refobjsubid + FROM pg_depend d + JOIN deps dp ON d.refclassid = dp.classid AND d.refobjid = dp.objid AND d.refobjsubid = dp.objsubid + ) + SELECT pg_describe_object(classid, objid, objsubid) as obj, + pg_identify_object(classid, objid, objsubid) as ident, + pg_identify_object_as_address(classid, objid, objsubid) as addr + FROM deps +) s +ORDER BY obj COLLATE "C", ident::text COLLATE "C"; + obj | ident | addr +----------------------------------------------------------+----------------------------------------------------------------------------+---------------------------------------------------------------------------- + edge e of property graph gt | ("property graph element",,,"e of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,e}",{}) + edge e of property graph gt | ("property graph element",,,"e of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,e}",{}) + edge e of property graph gt | ("property graph element",,,"e of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of property graph gt | ("property graph label",,,"e of create_property_graph_tests.gt") | ("property graph label","{create_property_graph_tests,gt,e}",{}) + label v1 of property graph gt | ("property graph label",,,"v1 of create_property_graph_tests.gt") | ("property graph label","{create_property_graph_tests,gt,v1}",{}) + label v1 of vertex v1 of property graph gt | ("property graph element label",,,"v1 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v1}",{}) + label v1 of vertex v1 of property graph gt | ("property graph element label",,,"v1 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v1}",{}) + label v2 of property graph gt | ("property graph label",,,"v2 of create_property_graph_tests.gt") | ("property graph label","{create_property_graph_tests,gt,v2}",{}) + label v2 of vertex v2 of property graph gt | ("property graph element label",,,"v2 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v2}",{}) + label v2 of vertex v2 of property graph gt | ("property graph element label",,,"v2 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v2}",{}) + property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property a of property graph gt | ("property graph property",,,"a of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,a}",{}) + property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property b of property graph gt | ("property graph property",,,"b of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,b}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of property graph gt | ("property graph property",,,"c of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,c}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of property graph gt | ("property graph property",,,"k1 of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,k1}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of property graph gt | ("property graph property",,,"k2 of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,k2}",{}) + property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property m of property graph gt | ("property graph property",,,"m of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,m}",{}) + property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property n of property graph gt | ("property graph property",,,"n of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,n}",{}) + type gt | (type,create_property_graph_tests,gt,create_property_graph_tests.gt) | (type,{create_property_graph_tests.gt},{}) + type gt[] | (type,create_property_graph_tests,_gt,create_property_graph_tests.gt[]) | (type,{create_property_graph_tests.gt[]},{}) + vertex v1 of property graph gt | ("property graph element",,,"v1 of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,v1}",{}) + vertex v2 of property graph gt | ("property graph element",,,"v2 of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,v2}",{}) +(52 rows) + \a\t SELECT pg_get_propgraphdef('g2'::regclass); CREATE PROPERTY GRAPH create_property_graph_tests.g2 diff --git a/src/test/regress/expected/event_trigger.out b/src/test/regress/expected/event_trigger.out index 065f586310f..ed8d5df397e 100644 --- a/src/test/regress/expected/event_trigger.out +++ b/src/test/regress/expected/event_trigger.out @@ -173,6 +173,23 @@ NOTICE: test_event_trigger: ddl_command_end CREATE USER MAPPING alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; NOTICE: test_event_trigger: ddl_command_end ALTER DEFAULT PRIVILEGES +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE TABLE t2x (i int PRIMARY KEY, j text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); +NOTICE: test_event_trigger: ddl_command_end CREATE PROPERTY GRAPH +DROP PROPERTY GRAPH gx; +NOTICE: test_event_trigger: ddl_command_end DROP PROPERTY GRAPH +DROP TABLE t1x, t2x; +NOTICE: test_event_trigger: ddl_command_end DROP TABLE -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; ERROR: permission denied to change owner of event trigger "regress_event_trigger" diff --git a/src/test/regress/expected/object_address.out b/src/test/regress/expected/object_address.out index 97227d67a54..5e53f0b092e 100644 --- a/src/test/regress/expected/object_address.out +++ b/src/test/regress/expected/object_address.out @@ -67,7 +67,9 @@ DECLARE BEGIN FOR objtype IN VALUES ('toast table'), ('index column'), ('sequence column'), ('toast table column'), ('view column'), ('materialized view column'), - ('property graph element'), ('property graph label'), ('property graph property') + ('property graph element'), ('property graph element label'), + ('property graph label'), ('property graph label property'), + ('property graph property') LOOP BEGIN PERFORM pg_get_object_address(objtype, '{one}', '{}'); @@ -84,7 +86,9 @@ WARNING: error for toast table column: unsupported object type "toast table col WARNING: error for view column: unsupported object type "view column" WARNING: error for materialized view column: unsupported object type "materialized view column" WARNING: error for property graph element: unsupported object type "property graph element" +WARNING: error for property graph element label: unrecognized object type "property graph element label" WARNING: error for property graph label: unsupported object type "property graph label" +WARNING: error for property graph label property: unrecognized object type "property graph label property" WARNING: error for property graph property: unsupported object type "property graph property" -- miscellaneous other errors select * from pg_get_object_address('operator of access method', '{btree,integer_ops,1}', '{int4,bool}'); @@ -593,7 +597,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace @@ -653,6 +659,8 @@ ORDER BY objects.classid, objects.objid, objects.objsubid; ("(""parameter ACL"",,,)")|("(""parameter ACL"",,)")|NULL ("(""property graph element"",,,)")|("(""property graph element"",,)")|NULL ("(""property graph label"",,,)")|("(""property graph label"",,)")|NULL +("(""property graph element label"",,,)")|("(""property graph element label"",,)")|NULL ("(""property graph property"",,,)")|("(""property graph property"",,)")|NULL +("(""property graph label property"",,,)")|("(""property graph label property"",,)")|NULL -- restore normal output mode \a\t diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..9608dd5c4af 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -298,6 +298,29 @@ SELECT (pg_identify_object(classid, objid, objsubid)).* refobjid = 'create_property_graph_tests.g2'::regclass ORDER BY 1, 2, 3, 4; +-- test object address functions with recursive dependency walk +-- covers all property graph object types including indirect dependents +SELECT * +FROM ( + WITH RECURSIVE deps (classid, objid, objsubid, refclassid, refobjid, refobjsubid) AS ( + SELECT classid, objid, objsubid, + refclassid, refobjid, refobjsubid + FROM pg_depend + WHERE refclassid = 'pg_class'::regclass AND + refobjid = 'create_property_graph_tests.gt'::regclass + UNION ALL + SELECT d.classid, d.objid, d.objsubid, + d.refclassid, d.refobjid, d.refobjsubid + FROM pg_depend d + JOIN deps dp ON d.refclassid = dp.classid AND d.refobjid = dp.objid AND d.refobjsubid = dp.objsubid + ) + SELECT pg_describe_object(classid, objid, objsubid) as obj, + pg_identify_object(classid, objid, objsubid) as ident, + pg_identify_object_as_address(classid, objid, objsubid) as addr + FROM deps +) s +ORDER BY obj COLLATE "C", ident::text COLLATE "C"; + \a\t SELECT pg_get_propgraphdef('g2'::regclass); SELECT pg_get_propgraphdef('g3'::regclass); diff --git a/src/test/regress/sql/event_trigger.sql b/src/test/regress/sql/event_trigger.sql index 32e9bb58c5e..271f443378b 100644 --- a/src/test/regress/sql/event_trigger.sql +++ b/src/test/regress/sql/event_trigger.sql @@ -143,6 +143,19 @@ create user mapping for regress_evt_user server useless_server; alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +CREATE TABLE t2x (i int PRIMARY KEY, j text); + +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); + +DROP PROPERTY GRAPH gx; +DROP TABLE t1x, t2x; + -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; diff --git a/src/test/regress/sql/object_address.sql b/src/test/regress/sql/object_address.sql index 1bbe9457c1c..27109d421c7 100644 --- a/src/test/regress/sql/object_address.sql +++ b/src/test/regress/sql/object_address.sql @@ -67,7 +67,9 @@ DECLARE BEGIN FOR objtype IN VALUES ('toast table'), ('index column'), ('sequence column'), ('toast table column'), ('view column'), ('materialized view column'), - ('property graph element'), ('property graph label'), ('property graph property') + ('property graph element'), ('property graph element label'), + ('property graph label'), ('property graph label property'), + ('property graph property') LOOP BEGIN PERFORM pg_get_object_address(objtype, '{one}', '{}'); @@ -282,7 +284,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace -- 2.34.1 --R84XrR4Hgw0dH3Ec-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v2] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-23 09:27 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-23 09:27 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing them to hit the default case and error out with "unsupported object class". During DROP PROPERTY GRAPH, this manifests when an event trigger is active, because pg_event_trigger_ddl_commands() calls these functions. The same code paths are also reachable via pg_identify_object() and pg_identify_object_as_address(). This commit adds the missing cases. Test coverage is added in object_address.sql for these two catalog types via the zero-OID test that exercises pg_identify_object() and pg_identify_object_as_address(). A test in event_trigger.sql verifies that DROP PROPERTY GRAPH works correctly when an event trigger is active. Author: Bertrand Drouvot <[email protected]> Reviewed-by: Michael Paquier <[email protected]> Reviewed-by: Ashutosh Bapat <[email protected]> Discussion: https://postgr.es/m/aej1DkLwhyZWmtxJ@bdtpg --- src/backend/catalog/objectaddress.c | 93 ++++++++++++++++++++ src/test/regress/expected/event_trigger.out | 17 ++++ src/test/regress/expected/object_address.out | 4 + src/test/regress/sql/event_trigger.sql | 13 +++ src/test/regress/sql/object_address.sql | 2 + 5 files changed, 129 insertions(+) 62.4% src/backend/catalog/ 25.6% src/test/regress/expected/ 11.8% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/event_trigger.out b/src/test/regress/expected/event_trigger.out index 065f586310f..ed8d5df397e 100644 --- a/src/test/regress/expected/event_trigger.out +++ b/src/test/regress/expected/event_trigger.out @@ -173,6 +173,23 @@ NOTICE: test_event_trigger: ddl_command_end CREATE USER MAPPING alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; NOTICE: test_event_trigger: ddl_command_end ALTER DEFAULT PRIVILEGES +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE TABLE t2x (i int PRIMARY KEY, j text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); +NOTICE: test_event_trigger: ddl_command_end CREATE PROPERTY GRAPH +DROP PROPERTY GRAPH gx; +NOTICE: test_event_trigger: ddl_command_end DROP PROPERTY GRAPH +DROP TABLE t1x, t2x; +NOTICE: test_event_trigger: ddl_command_end DROP TABLE -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; ERROR: permission denied to change owner of event trigger "regress_event_trigger" diff --git a/src/test/regress/expected/object_address.out b/src/test/regress/expected/object_address.out index 97227d67a54..729c3537f25 100644 --- a/src/test/regress/expected/object_address.out +++ b/src/test/regress/expected/object_address.out @@ -593,7 +593,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace @@ -653,6 +655,8 @@ ORDER BY objects.classid, objects.objid, objects.objsubid; ("(""parameter ACL"",,,)")|("(""parameter ACL"",,)")|NULL ("(""property graph element"",,,)")|("(""property graph element"",,)")|NULL ("(""property graph label"",,,)")|("(""property graph label"",,)")|NULL +("(""property graph element label"",,,)")|("(""property graph element label"",,)")|NULL ("(""property graph property"",,,)")|("(""property graph property"",,)")|NULL +("(""property graph label property"",,,)")|("(""property graph label property"",,)")|NULL -- restore normal output mode \a\t diff --git a/src/test/regress/sql/event_trigger.sql b/src/test/regress/sql/event_trigger.sql index 32e9bb58c5e..271f443378b 100644 --- a/src/test/regress/sql/event_trigger.sql +++ b/src/test/regress/sql/event_trigger.sql @@ -143,6 +143,19 @@ create user mapping for regress_evt_user server useless_server; alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +CREATE TABLE t2x (i int PRIMARY KEY, j text); + +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); + +DROP PROPERTY GRAPH gx; +DROP TABLE t1x, t2x; + -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; diff --git a/src/test/regress/sql/object_address.sql b/src/test/regress/sql/object_address.sql index 1bbe9457c1c..620dacf1045 100644 --- a/src/test/regress/sql/object_address.sql +++ b/src/test/regress/sql/object_address.sql @@ -282,7 +282,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace -- 2.34.1 --gtUR827Uq8d5gVsQ-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v2] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-23 09:27 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-23 09:27 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing them to hit the default case and error out with "unsupported object class". During DROP PROPERTY GRAPH, this manifests when an event trigger is active, because pg_event_trigger_ddl_commands() calls these functions. The same code paths are also reachable via pg_identify_object() and pg_identify_object_as_address(). This commit adds the missing cases. Test coverage is added in object_address.sql for these two catalog types via the zero-OID test that exercises pg_identify_object() and pg_identify_object_as_address(). A test in event_trigger.sql verifies that DROP PROPERTY GRAPH works correctly when an event trigger is active. Author: Bertrand Drouvot <[email protected]> Reviewed-by: Michael Paquier <[email protected]> Reviewed-by: Ashutosh Bapat <[email protected]> Discussion: https://postgr.es/m/aej1DkLwhyZWmtxJ@bdtpg --- src/backend/catalog/objectaddress.c | 93 ++++++++++++++++++++ src/test/regress/expected/event_trigger.out | 17 ++++ src/test/regress/expected/object_address.out | 4 + src/test/regress/sql/event_trigger.sql | 13 +++ src/test/regress/sql/object_address.sql | 2 + 5 files changed, 129 insertions(+) 62.4% src/backend/catalog/ 25.6% src/test/regress/expected/ 11.8% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/event_trigger.out b/src/test/regress/expected/event_trigger.out index 065f586310f..ed8d5df397e 100644 --- a/src/test/regress/expected/event_trigger.out +++ b/src/test/regress/expected/event_trigger.out @@ -173,6 +173,23 @@ NOTICE: test_event_trigger: ddl_command_end CREATE USER MAPPING alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; NOTICE: test_event_trigger: ddl_command_end ALTER DEFAULT PRIVILEGES +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE TABLE t2x (i int PRIMARY KEY, j text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); +NOTICE: test_event_trigger: ddl_command_end CREATE PROPERTY GRAPH +DROP PROPERTY GRAPH gx; +NOTICE: test_event_trigger: ddl_command_end DROP PROPERTY GRAPH +DROP TABLE t1x, t2x; +NOTICE: test_event_trigger: ddl_command_end DROP TABLE -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; ERROR: permission denied to change owner of event trigger "regress_event_trigger" diff --git a/src/test/regress/expected/object_address.out b/src/test/regress/expected/object_address.out index 97227d67a54..729c3537f25 100644 --- a/src/test/regress/expected/object_address.out +++ b/src/test/regress/expected/object_address.out @@ -593,7 +593,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace @@ -653,6 +655,8 @@ ORDER BY objects.classid, objects.objid, objects.objsubid; ("(""parameter ACL"",,,)")|("(""parameter ACL"",,)")|NULL ("(""property graph element"",,,)")|("(""property graph element"",,)")|NULL ("(""property graph label"",,,)")|("(""property graph label"",,)")|NULL +("(""property graph element label"",,,)")|("(""property graph element label"",,)")|NULL ("(""property graph property"",,,)")|("(""property graph property"",,)")|NULL +("(""property graph label property"",,,)")|("(""property graph label property"",,)")|NULL -- restore normal output mode \a\t diff --git a/src/test/regress/sql/event_trigger.sql b/src/test/regress/sql/event_trigger.sql index 32e9bb58c5e..271f443378b 100644 --- a/src/test/regress/sql/event_trigger.sql +++ b/src/test/regress/sql/event_trigger.sql @@ -143,6 +143,19 @@ create user mapping for regress_evt_user server useless_server; alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +CREATE TABLE t2x (i int PRIMARY KEY, j text); + +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); + +DROP PROPERTY GRAPH gx; +DROP TABLE t1x, t2x; + -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; diff --git a/src/test/regress/sql/object_address.sql b/src/test/regress/sql/object_address.sql index 1bbe9457c1c..620dacf1045 100644 --- a/src/test/regress/sql/object_address.sql +++ b/src/test/regress/sql/object_address.sql @@ -282,7 +282,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace -- 2.34.1 --gtUR827Uq8d5gVsQ-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v3] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-23 09:27 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-23 09:27 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing them to hit the default case and error out with "unsupported object class". During DROP PROPERTY GRAPH, this manifests when an event trigger is active, because pg_event_trigger_ddl_commands() calls these functions. The same code paths are also reachable via pg_identify_object() and pg_identify_object_as_address(). This commit adds the missing cases. Test coverage is added in object_address.sql for these two catalog types and in create_property_graph.sql covering all property graph object types. A test in event_trigger.sql verifies that DROP PROPERTY GRAPH works correctly when an event trigger is active. Author: Bertrand Drouvot <[email protected]> Reviewed-by: Michael Paquier <[email protected]> Reviewed-by: Ashutosh Bapat <[email protected]> Discussion: https://postgr.es/m/aej1DkLwhyZWmtxJ@bdtpg --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 78 ++++++++++++++++ src/test/regress/expected/event_trigger.out | 17 ++++ src/test/regress/expected/object_address.out | 10 +- .../regress/sql/create_property_graph.sql | 23 +++++ src/test/regress/sql/event_trigger.sql | 13 +++ src/test/regress/sql/object_address.sql | 6 +- 7 files changed, 238 insertions(+), 2 deletions(-) 14.7% src/backend/catalog/ 75.5% src/test/regress/expected/ 9.7% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..eb9e17fb727 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -752,6 +752,84 @@ SELECT (pg_identify_object(classid, objid, objsubid)).* type | create_property_graph_tests | g2 | create_property_graph_tests.g2 (21 rows) +-- test object address functions with recursive dependency walk +-- covers all property graph object types including indirect dependents +SELECT * +FROM ( + WITH RECURSIVE deps (classid, objid, objsubid, refclassid, refobjid, refobjsubid) AS ( + SELECT classid, objid, objsubid, + refclassid, refobjid, refobjsubid + FROM pg_depend + WHERE refclassid = 'pg_class'::regclass AND + refobjid = 'create_property_graph_tests.gt'::regclass + UNION ALL + SELECT d.classid, d.objid, d.objsubid, + d.refclassid, d.refobjid, d.refobjsubid + FROM pg_depend d + JOIN deps dp ON d.refclassid = dp.classid AND d.refobjid = dp.objid AND d.refobjsubid = dp.objsubid + ) + SELECT pg_describe_object(classid, objid, objsubid) as obj, + pg_identify_object(classid, objid, objsubid) as ident, + pg_identify_object_as_address(classid, objid, objsubid) as addr + FROM deps +) s +ORDER BY obj COLLATE "C", ident::text COLLATE "C"; + obj | ident | addr +----------------------------------------------------------+----------------------------------------------------------------------------+---------------------------------------------------------------------------- + edge e of property graph gt | ("property graph element",,,"e of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,e}",{}) + edge e of property graph gt | ("property graph element",,,"e of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,e}",{}) + edge e of property graph gt | ("property graph element",,,"e of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of property graph gt | ("property graph label",,,"e of create_property_graph_tests.gt") | ("property graph label","{create_property_graph_tests,gt,e}",{}) + label v1 of property graph gt | ("property graph label",,,"v1 of create_property_graph_tests.gt") | ("property graph label","{create_property_graph_tests,gt,v1}",{}) + label v1 of vertex v1 of property graph gt | ("property graph element label",,,"v1 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v1}",{}) + label v1 of vertex v1 of property graph gt | ("property graph element label",,,"v1 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v1}",{}) + label v2 of property graph gt | ("property graph label",,,"v2 of create_property_graph_tests.gt") | ("property graph label","{create_property_graph_tests,gt,v2}",{}) + label v2 of vertex v2 of property graph gt | ("property graph element label",,,"v2 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v2}",{}) + label v2 of vertex v2 of property graph gt | ("property graph element label",,,"v2 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v2}",{}) + property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property a of property graph gt | ("property graph property",,,"a of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,a}",{}) + property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property b of property graph gt | ("property graph property",,,"b of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,b}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of property graph gt | ("property graph property",,,"c of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,c}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of property graph gt | ("property graph property",,,"k1 of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,k1}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of property graph gt | ("property graph property",,,"k2 of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,k2}",{}) + property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property m of property graph gt | ("property graph property",,,"m of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,m}",{}) + property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property n of property graph gt | ("property graph property",,,"n of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,n}",{}) + type gt | (type,create_property_graph_tests,gt,create_property_graph_tests.gt) | (type,{create_property_graph_tests.gt},{}) + type gt[] | (type,create_property_graph_tests,_gt,create_property_graph_tests.gt[]) | (type,{create_property_graph_tests.gt[]},{}) + vertex v1 of property graph gt | ("property graph element",,,"v1 of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,v1}",{}) + vertex v2 of property graph gt | ("property graph element",,,"v2 of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,v2}",{}) +(52 rows) + \a\t SELECT pg_get_propgraphdef('g2'::regclass); CREATE PROPERTY GRAPH create_property_graph_tests.g2 diff --git a/src/test/regress/expected/event_trigger.out b/src/test/regress/expected/event_trigger.out index 065f586310f..ed8d5df397e 100644 --- a/src/test/regress/expected/event_trigger.out +++ b/src/test/regress/expected/event_trigger.out @@ -173,6 +173,23 @@ NOTICE: test_event_trigger: ddl_command_end CREATE USER MAPPING alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; NOTICE: test_event_trigger: ddl_command_end ALTER DEFAULT PRIVILEGES +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE TABLE t2x (i int PRIMARY KEY, j text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); +NOTICE: test_event_trigger: ddl_command_end CREATE PROPERTY GRAPH +DROP PROPERTY GRAPH gx; +NOTICE: test_event_trigger: ddl_command_end DROP PROPERTY GRAPH +DROP TABLE t1x, t2x; +NOTICE: test_event_trigger: ddl_command_end DROP TABLE -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; ERROR: permission denied to change owner of event trigger "regress_event_trigger" diff --git a/src/test/regress/expected/object_address.out b/src/test/regress/expected/object_address.out index 97227d67a54..5e53f0b092e 100644 --- a/src/test/regress/expected/object_address.out +++ b/src/test/regress/expected/object_address.out @@ -67,7 +67,9 @@ DECLARE BEGIN FOR objtype IN VALUES ('toast table'), ('index column'), ('sequence column'), ('toast table column'), ('view column'), ('materialized view column'), - ('property graph element'), ('property graph label'), ('property graph property') + ('property graph element'), ('property graph element label'), + ('property graph label'), ('property graph label property'), + ('property graph property') LOOP BEGIN PERFORM pg_get_object_address(objtype, '{one}', '{}'); @@ -84,7 +86,9 @@ WARNING: error for toast table column: unsupported object type "toast table col WARNING: error for view column: unsupported object type "view column" WARNING: error for materialized view column: unsupported object type "materialized view column" WARNING: error for property graph element: unsupported object type "property graph element" +WARNING: error for property graph element label: unrecognized object type "property graph element label" WARNING: error for property graph label: unsupported object type "property graph label" +WARNING: error for property graph label property: unrecognized object type "property graph label property" WARNING: error for property graph property: unsupported object type "property graph property" -- miscellaneous other errors select * from pg_get_object_address('operator of access method', '{btree,integer_ops,1}', '{int4,bool}'); @@ -593,7 +597,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace @@ -653,6 +659,8 @@ ORDER BY objects.classid, objects.objid, objects.objsubid; ("(""parameter ACL"",,,)")|("(""parameter ACL"",,)")|NULL ("(""property graph element"",,,)")|("(""property graph element"",,)")|NULL ("(""property graph label"",,,)")|("(""property graph label"",,)")|NULL +("(""property graph element label"",,,)")|("(""property graph element label"",,)")|NULL ("(""property graph property"",,,)")|("(""property graph property"",,)")|NULL +("(""property graph label property"",,,)")|("(""property graph label property"",,)")|NULL -- restore normal output mode \a\t diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..9608dd5c4af 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -298,6 +298,29 @@ SELECT (pg_identify_object(classid, objid, objsubid)).* refobjid = 'create_property_graph_tests.g2'::regclass ORDER BY 1, 2, 3, 4; +-- test object address functions with recursive dependency walk +-- covers all property graph object types including indirect dependents +SELECT * +FROM ( + WITH RECURSIVE deps (classid, objid, objsubid, refclassid, refobjid, refobjsubid) AS ( + SELECT classid, objid, objsubid, + refclassid, refobjid, refobjsubid + FROM pg_depend + WHERE refclassid = 'pg_class'::regclass AND + refobjid = 'create_property_graph_tests.gt'::regclass + UNION ALL + SELECT d.classid, d.objid, d.objsubid, + d.refclassid, d.refobjid, d.refobjsubid + FROM pg_depend d + JOIN deps dp ON d.refclassid = dp.classid AND d.refobjid = dp.objid AND d.refobjsubid = dp.objsubid + ) + SELECT pg_describe_object(classid, objid, objsubid) as obj, + pg_identify_object(classid, objid, objsubid) as ident, + pg_identify_object_as_address(classid, objid, objsubid) as addr + FROM deps +) s +ORDER BY obj COLLATE "C", ident::text COLLATE "C"; + \a\t SELECT pg_get_propgraphdef('g2'::regclass); SELECT pg_get_propgraphdef('g3'::regclass); diff --git a/src/test/regress/sql/event_trigger.sql b/src/test/regress/sql/event_trigger.sql index 32e9bb58c5e..271f443378b 100644 --- a/src/test/regress/sql/event_trigger.sql +++ b/src/test/regress/sql/event_trigger.sql @@ -143,6 +143,19 @@ create user mapping for regress_evt_user server useless_server; alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +CREATE TABLE t2x (i int PRIMARY KEY, j text); + +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); + +DROP PROPERTY GRAPH gx; +DROP TABLE t1x, t2x; + -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; diff --git a/src/test/regress/sql/object_address.sql b/src/test/regress/sql/object_address.sql index 1bbe9457c1c..27109d421c7 100644 --- a/src/test/regress/sql/object_address.sql +++ b/src/test/regress/sql/object_address.sql @@ -67,7 +67,9 @@ DECLARE BEGIN FOR objtype IN VALUES ('toast table'), ('index column'), ('sequence column'), ('toast table column'), ('view column'), ('materialized view column'), - ('property graph element'), ('property graph label'), ('property graph property') + ('property graph element'), ('property graph element label'), + ('property graph label'), ('property graph label property'), + ('property graph property') LOOP BEGIN PERFORM pg_get_object_address(objtype, '{one}', '{}'); @@ -282,7 +284,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace -- 2.34.1 --R84XrR4Hgw0dH3Ec-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v3] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-23 09:27 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-23 09:27 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing them to hit the default case and error out with "unsupported object class". During DROP PROPERTY GRAPH, this manifests when an event trigger is active, because pg_event_trigger_ddl_commands() calls these functions. The same code paths are also reachable via pg_identify_object() and pg_identify_object_as_address(). This commit adds the missing cases. Test coverage is added in object_address.sql for these two catalog types and in create_property_graph.sql covering all property graph object types. A test in event_trigger.sql verifies that DROP PROPERTY GRAPH works correctly when an event trigger is active. Author: Bertrand Drouvot <[email protected]> Reviewed-by: Michael Paquier <[email protected]> Reviewed-by: Ashutosh Bapat <[email protected]> Discussion: https://postgr.es/m/aej1DkLwhyZWmtxJ@bdtpg --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 78 ++++++++++++++++ src/test/regress/expected/event_trigger.out | 17 ++++ src/test/regress/expected/object_address.out | 10 +- .../regress/sql/create_property_graph.sql | 23 +++++ src/test/regress/sql/event_trigger.sql | 13 +++ src/test/regress/sql/object_address.sql | 6 +- 7 files changed, 238 insertions(+), 2 deletions(-) 14.7% src/backend/catalog/ 75.5% src/test/regress/expected/ 9.7% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..eb9e17fb727 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -752,6 +752,84 @@ SELECT (pg_identify_object(classid, objid, objsubid)).* type | create_property_graph_tests | g2 | create_property_graph_tests.g2 (21 rows) +-- test object address functions with recursive dependency walk +-- covers all property graph object types including indirect dependents +SELECT * +FROM ( + WITH RECURSIVE deps (classid, objid, objsubid, refclassid, refobjid, refobjsubid) AS ( + SELECT classid, objid, objsubid, + refclassid, refobjid, refobjsubid + FROM pg_depend + WHERE refclassid = 'pg_class'::regclass AND + refobjid = 'create_property_graph_tests.gt'::regclass + UNION ALL + SELECT d.classid, d.objid, d.objsubid, + d.refclassid, d.refobjid, d.refobjsubid + FROM pg_depend d + JOIN deps dp ON d.refclassid = dp.classid AND d.refobjid = dp.objid AND d.refobjsubid = dp.objsubid + ) + SELECT pg_describe_object(classid, objid, objsubid) as obj, + pg_identify_object(classid, objid, objsubid) as ident, + pg_identify_object_as_address(classid, objid, objsubid) as addr + FROM deps +) s +ORDER BY obj COLLATE "C", ident::text COLLATE "C"; + obj | ident | addr +----------------------------------------------------------+----------------------------------------------------------------------------+---------------------------------------------------------------------------- + edge e of property graph gt | ("property graph element",,,"e of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,e}",{}) + edge e of property graph gt | ("property graph element",,,"e of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,e}",{}) + edge e of property graph gt | ("property graph element",,,"e of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of property graph gt | ("property graph label",,,"e of create_property_graph_tests.gt") | ("property graph label","{create_property_graph_tests,gt,e}",{}) + label v1 of property graph gt | ("property graph label",,,"v1 of create_property_graph_tests.gt") | ("property graph label","{create_property_graph_tests,gt,v1}",{}) + label v1 of vertex v1 of property graph gt | ("property graph element label",,,"v1 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v1}",{}) + label v1 of vertex v1 of property graph gt | ("property graph element label",,,"v1 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v1}",{}) + label v2 of property graph gt | ("property graph label",,,"v2 of create_property_graph_tests.gt") | ("property graph label","{create_property_graph_tests,gt,v2}",{}) + label v2 of vertex v2 of property graph gt | ("property graph element label",,,"v2 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v2}",{}) + label v2 of vertex v2 of property graph gt | ("property graph element label",,,"v2 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v2}",{}) + property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property a of property graph gt | ("property graph property",,,"a of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,a}",{}) + property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property b of property graph gt | ("property graph property",,,"b of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,b}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of property graph gt | ("property graph property",,,"c of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,c}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of property graph gt | ("property graph property",,,"k1 of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,k1}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of property graph gt | ("property graph property",,,"k2 of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,k2}",{}) + property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property m of property graph gt | ("property graph property",,,"m of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,m}",{}) + property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property n of property graph gt | ("property graph property",,,"n of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,n}",{}) + type gt | (type,create_property_graph_tests,gt,create_property_graph_tests.gt) | (type,{create_property_graph_tests.gt},{}) + type gt[] | (type,create_property_graph_tests,_gt,create_property_graph_tests.gt[]) | (type,{create_property_graph_tests.gt[]},{}) + vertex v1 of property graph gt | ("property graph element",,,"v1 of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,v1}",{}) + vertex v2 of property graph gt | ("property graph element",,,"v2 of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,v2}",{}) +(52 rows) + \a\t SELECT pg_get_propgraphdef('g2'::regclass); CREATE PROPERTY GRAPH create_property_graph_tests.g2 diff --git a/src/test/regress/expected/event_trigger.out b/src/test/regress/expected/event_trigger.out index 065f586310f..ed8d5df397e 100644 --- a/src/test/regress/expected/event_trigger.out +++ b/src/test/regress/expected/event_trigger.out @@ -173,6 +173,23 @@ NOTICE: test_event_trigger: ddl_command_end CREATE USER MAPPING alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; NOTICE: test_event_trigger: ddl_command_end ALTER DEFAULT PRIVILEGES +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE TABLE t2x (i int PRIMARY KEY, j text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); +NOTICE: test_event_trigger: ddl_command_end CREATE PROPERTY GRAPH +DROP PROPERTY GRAPH gx; +NOTICE: test_event_trigger: ddl_command_end DROP PROPERTY GRAPH +DROP TABLE t1x, t2x; +NOTICE: test_event_trigger: ddl_command_end DROP TABLE -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; ERROR: permission denied to change owner of event trigger "regress_event_trigger" diff --git a/src/test/regress/expected/object_address.out b/src/test/regress/expected/object_address.out index 97227d67a54..5e53f0b092e 100644 --- a/src/test/regress/expected/object_address.out +++ b/src/test/regress/expected/object_address.out @@ -67,7 +67,9 @@ DECLARE BEGIN FOR objtype IN VALUES ('toast table'), ('index column'), ('sequence column'), ('toast table column'), ('view column'), ('materialized view column'), - ('property graph element'), ('property graph label'), ('property graph property') + ('property graph element'), ('property graph element label'), + ('property graph label'), ('property graph label property'), + ('property graph property') LOOP BEGIN PERFORM pg_get_object_address(objtype, '{one}', '{}'); @@ -84,7 +86,9 @@ WARNING: error for toast table column: unsupported object type "toast table col WARNING: error for view column: unsupported object type "view column" WARNING: error for materialized view column: unsupported object type "materialized view column" WARNING: error for property graph element: unsupported object type "property graph element" +WARNING: error for property graph element label: unrecognized object type "property graph element label" WARNING: error for property graph label: unsupported object type "property graph label" +WARNING: error for property graph label property: unrecognized object type "property graph label property" WARNING: error for property graph property: unsupported object type "property graph property" -- miscellaneous other errors select * from pg_get_object_address('operator of access method', '{btree,integer_ops,1}', '{int4,bool}'); @@ -593,7 +597,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace @@ -653,6 +659,8 @@ ORDER BY objects.classid, objects.objid, objects.objsubid; ("(""parameter ACL"",,,)")|("(""parameter ACL"",,)")|NULL ("(""property graph element"",,,)")|("(""property graph element"",,)")|NULL ("(""property graph label"",,,)")|("(""property graph label"",,)")|NULL +("(""property graph element label"",,,)")|("(""property graph element label"",,)")|NULL ("(""property graph property"",,,)")|("(""property graph property"",,)")|NULL +("(""property graph label property"",,,)")|("(""property graph label property"",,)")|NULL -- restore normal output mode \a\t diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..9608dd5c4af 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -298,6 +298,29 @@ SELECT (pg_identify_object(classid, objid, objsubid)).* refobjid = 'create_property_graph_tests.g2'::regclass ORDER BY 1, 2, 3, 4; +-- test object address functions with recursive dependency walk +-- covers all property graph object types including indirect dependents +SELECT * +FROM ( + WITH RECURSIVE deps (classid, objid, objsubid, refclassid, refobjid, refobjsubid) AS ( + SELECT classid, objid, objsubid, + refclassid, refobjid, refobjsubid + FROM pg_depend + WHERE refclassid = 'pg_class'::regclass AND + refobjid = 'create_property_graph_tests.gt'::regclass + UNION ALL + SELECT d.classid, d.objid, d.objsubid, + d.refclassid, d.refobjid, d.refobjsubid + FROM pg_depend d + JOIN deps dp ON d.refclassid = dp.classid AND d.refobjid = dp.objid AND d.refobjsubid = dp.objsubid + ) + SELECT pg_describe_object(classid, objid, objsubid) as obj, + pg_identify_object(classid, objid, objsubid) as ident, + pg_identify_object_as_address(classid, objid, objsubid) as addr + FROM deps +) s +ORDER BY obj COLLATE "C", ident::text COLLATE "C"; + \a\t SELECT pg_get_propgraphdef('g2'::regclass); SELECT pg_get_propgraphdef('g3'::regclass); diff --git a/src/test/regress/sql/event_trigger.sql b/src/test/regress/sql/event_trigger.sql index 32e9bb58c5e..271f443378b 100644 --- a/src/test/regress/sql/event_trigger.sql +++ b/src/test/regress/sql/event_trigger.sql @@ -143,6 +143,19 @@ create user mapping for regress_evt_user server useless_server; alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +CREATE TABLE t2x (i int PRIMARY KEY, j text); + +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); + +DROP PROPERTY GRAPH gx; +DROP TABLE t1x, t2x; + -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; diff --git a/src/test/regress/sql/object_address.sql b/src/test/regress/sql/object_address.sql index 1bbe9457c1c..27109d421c7 100644 --- a/src/test/regress/sql/object_address.sql +++ b/src/test/regress/sql/object_address.sql @@ -67,7 +67,9 @@ DECLARE BEGIN FOR objtype IN VALUES ('toast table'), ('index column'), ('sequence column'), ('toast table column'), ('view column'), ('materialized view column'), - ('property graph element'), ('property graph label'), ('property graph property') + ('property graph element'), ('property graph element label'), + ('property graph label'), ('property graph label property'), + ('property graph property') LOOP BEGIN PERFORM pg_get_object_address(objtype, '{one}', '{}'); @@ -282,7 +284,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace -- 2.34.1 --R84XrR4Hgw0dH3Ec-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v3] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-23 09:27 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-23 09:27 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing them to hit the default case and error out with "unsupported object class". During DROP PROPERTY GRAPH, this manifests when an event trigger is active, because pg_event_trigger_ddl_commands() calls these functions. The same code paths are also reachable via pg_identify_object() and pg_identify_object_as_address(). This commit adds the missing cases. Test coverage is added in object_address.sql for these two catalog types and in create_property_graph.sql covering all property graph object types. A test in event_trigger.sql verifies that DROP PROPERTY GRAPH works correctly when an event trigger is active. Author: Bertrand Drouvot <[email protected]> Reviewed-by: Michael Paquier <[email protected]> Reviewed-by: Ashutosh Bapat <[email protected]> Discussion: https://postgr.es/m/aej1DkLwhyZWmtxJ@bdtpg --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 78 ++++++++++++++++ src/test/regress/expected/event_trigger.out | 17 ++++ src/test/regress/expected/object_address.out | 10 +- .../regress/sql/create_property_graph.sql | 23 +++++ src/test/regress/sql/event_trigger.sql | 13 +++ src/test/regress/sql/object_address.sql | 6 +- 7 files changed, 238 insertions(+), 2 deletions(-) 14.7% src/backend/catalog/ 75.5% src/test/regress/expected/ 9.7% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..eb9e17fb727 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -752,6 +752,84 @@ SELECT (pg_identify_object(classid, objid, objsubid)).* type | create_property_graph_tests | g2 | create_property_graph_tests.g2 (21 rows) +-- test object address functions with recursive dependency walk +-- covers all property graph object types including indirect dependents +SELECT * +FROM ( + WITH RECURSIVE deps (classid, objid, objsubid, refclassid, refobjid, refobjsubid) AS ( + SELECT classid, objid, objsubid, + refclassid, refobjid, refobjsubid + FROM pg_depend + WHERE refclassid = 'pg_class'::regclass AND + refobjid = 'create_property_graph_tests.gt'::regclass + UNION ALL + SELECT d.classid, d.objid, d.objsubid, + d.refclassid, d.refobjid, d.refobjsubid + FROM pg_depend d + JOIN deps dp ON d.refclassid = dp.classid AND d.refobjid = dp.objid AND d.refobjsubid = dp.objsubid + ) + SELECT pg_describe_object(classid, objid, objsubid) as obj, + pg_identify_object(classid, objid, objsubid) as ident, + pg_identify_object_as_address(classid, objid, objsubid) as addr + FROM deps +) s +ORDER BY obj COLLATE "C", ident::text COLLATE "C"; + obj | ident | addr +----------------------------------------------------------+----------------------------------------------------------------------------+---------------------------------------------------------------------------- + edge e of property graph gt | ("property graph element",,,"e of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,e}",{}) + edge e of property graph gt | ("property graph element",,,"e of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,e}",{}) + edge e of property graph gt | ("property graph element",,,"e of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of property graph gt | ("property graph label",,,"e of create_property_graph_tests.gt") | ("property graph label","{create_property_graph_tests,gt,e}",{}) + label v1 of property graph gt | ("property graph label",,,"v1 of create_property_graph_tests.gt") | ("property graph label","{create_property_graph_tests,gt,v1}",{}) + label v1 of vertex v1 of property graph gt | ("property graph element label",,,"v1 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v1}",{}) + label v1 of vertex v1 of property graph gt | ("property graph element label",,,"v1 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v1}",{}) + label v2 of property graph gt | ("property graph label",,,"v2 of create_property_graph_tests.gt") | ("property graph label","{create_property_graph_tests,gt,v2}",{}) + label v2 of vertex v2 of property graph gt | ("property graph element label",,,"v2 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v2}",{}) + label v2 of vertex v2 of property graph gt | ("property graph element label",,,"v2 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v2}",{}) + property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property a of property graph gt | ("property graph property",,,"a of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,a}",{}) + property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property b of property graph gt | ("property graph property",,,"b of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,b}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of property graph gt | ("property graph property",,,"c of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,c}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of property graph gt | ("property graph property",,,"k1 of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,k1}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of property graph gt | ("property graph property",,,"k2 of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,k2}",{}) + property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property m of property graph gt | ("property graph property",,,"m of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,m}",{}) + property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property n of property graph gt | ("property graph property",,,"n of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,n}",{}) + type gt | (type,create_property_graph_tests,gt,create_property_graph_tests.gt) | (type,{create_property_graph_tests.gt},{}) + type gt[] | (type,create_property_graph_tests,_gt,create_property_graph_tests.gt[]) | (type,{create_property_graph_tests.gt[]},{}) + vertex v1 of property graph gt | ("property graph element",,,"v1 of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,v1}",{}) + vertex v2 of property graph gt | ("property graph element",,,"v2 of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,v2}",{}) +(52 rows) + \a\t SELECT pg_get_propgraphdef('g2'::regclass); CREATE PROPERTY GRAPH create_property_graph_tests.g2 diff --git a/src/test/regress/expected/event_trigger.out b/src/test/regress/expected/event_trigger.out index 065f586310f..ed8d5df397e 100644 --- a/src/test/regress/expected/event_trigger.out +++ b/src/test/regress/expected/event_trigger.out @@ -173,6 +173,23 @@ NOTICE: test_event_trigger: ddl_command_end CREATE USER MAPPING alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; NOTICE: test_event_trigger: ddl_command_end ALTER DEFAULT PRIVILEGES +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE TABLE t2x (i int PRIMARY KEY, j text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); +NOTICE: test_event_trigger: ddl_command_end CREATE PROPERTY GRAPH +DROP PROPERTY GRAPH gx; +NOTICE: test_event_trigger: ddl_command_end DROP PROPERTY GRAPH +DROP TABLE t1x, t2x; +NOTICE: test_event_trigger: ddl_command_end DROP TABLE -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; ERROR: permission denied to change owner of event trigger "regress_event_trigger" diff --git a/src/test/regress/expected/object_address.out b/src/test/regress/expected/object_address.out index 97227d67a54..5e53f0b092e 100644 --- a/src/test/regress/expected/object_address.out +++ b/src/test/regress/expected/object_address.out @@ -67,7 +67,9 @@ DECLARE BEGIN FOR objtype IN VALUES ('toast table'), ('index column'), ('sequence column'), ('toast table column'), ('view column'), ('materialized view column'), - ('property graph element'), ('property graph label'), ('property graph property') + ('property graph element'), ('property graph element label'), + ('property graph label'), ('property graph label property'), + ('property graph property') LOOP BEGIN PERFORM pg_get_object_address(objtype, '{one}', '{}'); @@ -84,7 +86,9 @@ WARNING: error for toast table column: unsupported object type "toast table col WARNING: error for view column: unsupported object type "view column" WARNING: error for materialized view column: unsupported object type "materialized view column" WARNING: error for property graph element: unsupported object type "property graph element" +WARNING: error for property graph element label: unrecognized object type "property graph element label" WARNING: error for property graph label: unsupported object type "property graph label" +WARNING: error for property graph label property: unrecognized object type "property graph label property" WARNING: error for property graph property: unsupported object type "property graph property" -- miscellaneous other errors select * from pg_get_object_address('operator of access method', '{btree,integer_ops,1}', '{int4,bool}'); @@ -593,7 +597,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace @@ -653,6 +659,8 @@ ORDER BY objects.classid, objects.objid, objects.objsubid; ("(""parameter ACL"",,,)")|("(""parameter ACL"",,)")|NULL ("(""property graph element"",,,)")|("(""property graph element"",,)")|NULL ("(""property graph label"",,,)")|("(""property graph label"",,)")|NULL +("(""property graph element label"",,,)")|("(""property graph element label"",,)")|NULL ("(""property graph property"",,,)")|("(""property graph property"",,)")|NULL +("(""property graph label property"",,,)")|("(""property graph label property"",,)")|NULL -- restore normal output mode \a\t diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..9608dd5c4af 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -298,6 +298,29 @@ SELECT (pg_identify_object(classid, objid, objsubid)).* refobjid = 'create_property_graph_tests.g2'::regclass ORDER BY 1, 2, 3, 4; +-- test object address functions with recursive dependency walk +-- covers all property graph object types including indirect dependents +SELECT * +FROM ( + WITH RECURSIVE deps (classid, objid, objsubid, refclassid, refobjid, refobjsubid) AS ( + SELECT classid, objid, objsubid, + refclassid, refobjid, refobjsubid + FROM pg_depend + WHERE refclassid = 'pg_class'::regclass AND + refobjid = 'create_property_graph_tests.gt'::regclass + UNION ALL + SELECT d.classid, d.objid, d.objsubid, + d.refclassid, d.refobjid, d.refobjsubid + FROM pg_depend d + JOIN deps dp ON d.refclassid = dp.classid AND d.refobjid = dp.objid AND d.refobjsubid = dp.objsubid + ) + SELECT pg_describe_object(classid, objid, objsubid) as obj, + pg_identify_object(classid, objid, objsubid) as ident, + pg_identify_object_as_address(classid, objid, objsubid) as addr + FROM deps +) s +ORDER BY obj COLLATE "C", ident::text COLLATE "C"; + \a\t SELECT pg_get_propgraphdef('g2'::regclass); SELECT pg_get_propgraphdef('g3'::regclass); diff --git a/src/test/regress/sql/event_trigger.sql b/src/test/regress/sql/event_trigger.sql index 32e9bb58c5e..271f443378b 100644 --- a/src/test/regress/sql/event_trigger.sql +++ b/src/test/regress/sql/event_trigger.sql @@ -143,6 +143,19 @@ create user mapping for regress_evt_user server useless_server; alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +CREATE TABLE t2x (i int PRIMARY KEY, j text); + +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); + +DROP PROPERTY GRAPH gx; +DROP TABLE t1x, t2x; + -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; diff --git a/src/test/regress/sql/object_address.sql b/src/test/regress/sql/object_address.sql index 1bbe9457c1c..27109d421c7 100644 --- a/src/test/regress/sql/object_address.sql +++ b/src/test/regress/sql/object_address.sql @@ -67,7 +67,9 @@ DECLARE BEGIN FOR objtype IN VALUES ('toast table'), ('index column'), ('sequence column'), ('toast table column'), ('view column'), ('materialized view column'), - ('property graph element'), ('property graph label'), ('property graph property') + ('property graph element'), ('property graph element label'), + ('property graph label'), ('property graph label property'), + ('property graph property') LOOP BEGIN PERFORM pg_get_object_address(objtype, '{one}', '{}'); @@ -282,7 +284,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace -- 2.34.1 --R84XrR4Hgw0dH3Ec-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v2] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-23 09:27 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-23 09:27 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing them to hit the default case and error out with "unsupported object class". During DROP PROPERTY GRAPH, this manifests when an event trigger is active, because pg_event_trigger_ddl_commands() calls these functions. The same code paths are also reachable via pg_identify_object() and pg_identify_object_as_address(). This commit adds the missing cases. Test coverage is added in object_address.sql for these two catalog types via the zero-OID test that exercises pg_identify_object() and pg_identify_object_as_address(). A test in event_trigger.sql verifies that DROP PROPERTY GRAPH works correctly when an event trigger is active. Author: Bertrand Drouvot <[email protected]> Reviewed-by: Michael Paquier <[email protected]> Reviewed-by: Ashutosh Bapat <[email protected]> Discussion: https://postgr.es/m/aej1DkLwhyZWmtxJ@bdtpg --- src/backend/catalog/objectaddress.c | 93 ++++++++++++++++++++ src/test/regress/expected/event_trigger.out | 17 ++++ src/test/regress/expected/object_address.out | 4 + src/test/regress/sql/event_trigger.sql | 13 +++ src/test/regress/sql/object_address.sql | 2 + 5 files changed, 129 insertions(+) 62.4% src/backend/catalog/ 25.6% src/test/regress/expected/ 11.8% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/event_trigger.out b/src/test/regress/expected/event_trigger.out index 065f586310f..ed8d5df397e 100644 --- a/src/test/regress/expected/event_trigger.out +++ b/src/test/regress/expected/event_trigger.out @@ -173,6 +173,23 @@ NOTICE: test_event_trigger: ddl_command_end CREATE USER MAPPING alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; NOTICE: test_event_trigger: ddl_command_end ALTER DEFAULT PRIVILEGES +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE TABLE t2x (i int PRIMARY KEY, j text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); +NOTICE: test_event_trigger: ddl_command_end CREATE PROPERTY GRAPH +DROP PROPERTY GRAPH gx; +NOTICE: test_event_trigger: ddl_command_end DROP PROPERTY GRAPH +DROP TABLE t1x, t2x; +NOTICE: test_event_trigger: ddl_command_end DROP TABLE -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; ERROR: permission denied to change owner of event trigger "regress_event_trigger" diff --git a/src/test/regress/expected/object_address.out b/src/test/regress/expected/object_address.out index 97227d67a54..729c3537f25 100644 --- a/src/test/regress/expected/object_address.out +++ b/src/test/regress/expected/object_address.out @@ -593,7 +593,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace @@ -653,6 +655,8 @@ ORDER BY objects.classid, objects.objid, objects.objsubid; ("(""parameter ACL"",,,)")|("(""parameter ACL"",,)")|NULL ("(""property graph element"",,,)")|("(""property graph element"",,)")|NULL ("(""property graph label"",,,)")|("(""property graph label"",,)")|NULL +("(""property graph element label"",,,)")|("(""property graph element label"",,)")|NULL ("(""property graph property"",,,)")|("(""property graph property"",,)")|NULL +("(""property graph label property"",,,)")|("(""property graph label property"",,)")|NULL -- restore normal output mode \a\t diff --git a/src/test/regress/sql/event_trigger.sql b/src/test/regress/sql/event_trigger.sql index 32e9bb58c5e..271f443378b 100644 --- a/src/test/regress/sql/event_trigger.sql +++ b/src/test/regress/sql/event_trigger.sql @@ -143,6 +143,19 @@ create user mapping for regress_evt_user server useless_server; alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +CREATE TABLE t2x (i int PRIMARY KEY, j text); + +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); + +DROP PROPERTY GRAPH gx; +DROP TABLE t1x, t2x; + -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; diff --git a/src/test/regress/sql/object_address.sql b/src/test/regress/sql/object_address.sql index 1bbe9457c1c..620dacf1045 100644 --- a/src/test/regress/sql/object_address.sql +++ b/src/test/regress/sql/object_address.sql @@ -282,7 +282,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace -- 2.34.1 --gtUR827Uq8d5gVsQ-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v3] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-23 09:27 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-23 09:27 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing them to hit the default case and error out with "unsupported object class". During DROP PROPERTY GRAPH, this manifests when an event trigger is active, because pg_event_trigger_ddl_commands() calls these functions. The same code paths are also reachable via pg_identify_object() and pg_identify_object_as_address(). This commit adds the missing cases. Test coverage is added in object_address.sql for these two catalog types and in create_property_graph.sql covering all property graph object types. A test in event_trigger.sql verifies that DROP PROPERTY GRAPH works correctly when an event trigger is active. Author: Bertrand Drouvot <[email protected]> Reviewed-by: Michael Paquier <[email protected]> Reviewed-by: Ashutosh Bapat <[email protected]> Discussion: https://postgr.es/m/aej1DkLwhyZWmtxJ@bdtpg --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 78 ++++++++++++++++ src/test/regress/expected/event_trigger.out | 17 ++++ src/test/regress/expected/object_address.out | 10 +- .../regress/sql/create_property_graph.sql | 23 +++++ src/test/regress/sql/event_trigger.sql | 13 +++ src/test/regress/sql/object_address.sql | 6 +- 7 files changed, 238 insertions(+), 2 deletions(-) 14.7% src/backend/catalog/ 75.5% src/test/regress/expected/ 9.7% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..eb9e17fb727 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -752,6 +752,84 @@ SELECT (pg_identify_object(classid, objid, objsubid)).* type | create_property_graph_tests | g2 | create_property_graph_tests.g2 (21 rows) +-- test object address functions with recursive dependency walk +-- covers all property graph object types including indirect dependents +SELECT * +FROM ( + WITH RECURSIVE deps (classid, objid, objsubid, refclassid, refobjid, refobjsubid) AS ( + SELECT classid, objid, objsubid, + refclassid, refobjid, refobjsubid + FROM pg_depend + WHERE refclassid = 'pg_class'::regclass AND + refobjid = 'create_property_graph_tests.gt'::regclass + UNION ALL + SELECT d.classid, d.objid, d.objsubid, + d.refclassid, d.refobjid, d.refobjsubid + FROM pg_depend d + JOIN deps dp ON d.refclassid = dp.classid AND d.refobjid = dp.objid AND d.refobjsubid = dp.objsubid + ) + SELECT pg_describe_object(classid, objid, objsubid) as obj, + pg_identify_object(classid, objid, objsubid) as ident, + pg_identify_object_as_address(classid, objid, objsubid) as addr + FROM deps +) s +ORDER BY obj COLLATE "C", ident::text COLLATE "C"; + obj | ident | addr +----------------------------------------------------------+----------------------------------------------------------------------------+---------------------------------------------------------------------------- + edge e of property graph gt | ("property graph element",,,"e of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,e}",{}) + edge e of property graph gt | ("property graph element",,,"e of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,e}",{}) + edge e of property graph gt | ("property graph element",,,"e of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of property graph gt | ("property graph label",,,"e of create_property_graph_tests.gt") | ("property graph label","{create_property_graph_tests,gt,e}",{}) + label v1 of property graph gt | ("property graph label",,,"v1 of create_property_graph_tests.gt") | ("property graph label","{create_property_graph_tests,gt,v1}",{}) + label v1 of vertex v1 of property graph gt | ("property graph element label",,,"v1 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v1}",{}) + label v1 of vertex v1 of property graph gt | ("property graph element label",,,"v1 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v1}",{}) + label v2 of property graph gt | ("property graph label",,,"v2 of create_property_graph_tests.gt") | ("property graph label","{create_property_graph_tests,gt,v2}",{}) + label v2 of vertex v2 of property graph gt | ("property graph element label",,,"v2 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v2}",{}) + label v2 of vertex v2 of property graph gt | ("property graph element label",,,"v2 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v2}",{}) + property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property a of property graph gt | ("property graph property",,,"a of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,a}",{}) + property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property b of property graph gt | ("property graph property",,,"b of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,b}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of property graph gt | ("property graph property",,,"c of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,c}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of property graph gt | ("property graph property",,,"k1 of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,k1}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of property graph gt | ("property graph property",,,"k2 of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,k2}",{}) + property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property m of property graph gt | ("property graph property",,,"m of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,m}",{}) + property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property n of property graph gt | ("property graph property",,,"n of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,n}",{}) + type gt | (type,create_property_graph_tests,gt,create_property_graph_tests.gt) | (type,{create_property_graph_tests.gt},{}) + type gt[] | (type,create_property_graph_tests,_gt,create_property_graph_tests.gt[]) | (type,{create_property_graph_tests.gt[]},{}) + vertex v1 of property graph gt | ("property graph element",,,"v1 of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,v1}",{}) + vertex v2 of property graph gt | ("property graph element",,,"v2 of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,v2}",{}) +(52 rows) + \a\t SELECT pg_get_propgraphdef('g2'::regclass); CREATE PROPERTY GRAPH create_property_graph_tests.g2 diff --git a/src/test/regress/expected/event_trigger.out b/src/test/regress/expected/event_trigger.out index 065f586310f..ed8d5df397e 100644 --- a/src/test/regress/expected/event_trigger.out +++ b/src/test/regress/expected/event_trigger.out @@ -173,6 +173,23 @@ NOTICE: test_event_trigger: ddl_command_end CREATE USER MAPPING alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; NOTICE: test_event_trigger: ddl_command_end ALTER DEFAULT PRIVILEGES +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE TABLE t2x (i int PRIMARY KEY, j text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); +NOTICE: test_event_trigger: ddl_command_end CREATE PROPERTY GRAPH +DROP PROPERTY GRAPH gx; +NOTICE: test_event_trigger: ddl_command_end DROP PROPERTY GRAPH +DROP TABLE t1x, t2x; +NOTICE: test_event_trigger: ddl_command_end DROP TABLE -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; ERROR: permission denied to change owner of event trigger "regress_event_trigger" diff --git a/src/test/regress/expected/object_address.out b/src/test/regress/expected/object_address.out index 97227d67a54..5e53f0b092e 100644 --- a/src/test/regress/expected/object_address.out +++ b/src/test/regress/expected/object_address.out @@ -67,7 +67,9 @@ DECLARE BEGIN FOR objtype IN VALUES ('toast table'), ('index column'), ('sequence column'), ('toast table column'), ('view column'), ('materialized view column'), - ('property graph element'), ('property graph label'), ('property graph property') + ('property graph element'), ('property graph element label'), + ('property graph label'), ('property graph label property'), + ('property graph property') LOOP BEGIN PERFORM pg_get_object_address(objtype, '{one}', '{}'); @@ -84,7 +86,9 @@ WARNING: error for toast table column: unsupported object type "toast table col WARNING: error for view column: unsupported object type "view column" WARNING: error for materialized view column: unsupported object type "materialized view column" WARNING: error for property graph element: unsupported object type "property graph element" +WARNING: error for property graph element label: unrecognized object type "property graph element label" WARNING: error for property graph label: unsupported object type "property graph label" +WARNING: error for property graph label property: unrecognized object type "property graph label property" WARNING: error for property graph property: unsupported object type "property graph property" -- miscellaneous other errors select * from pg_get_object_address('operator of access method', '{btree,integer_ops,1}', '{int4,bool}'); @@ -593,7 +597,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace @@ -653,6 +659,8 @@ ORDER BY objects.classid, objects.objid, objects.objsubid; ("(""parameter ACL"",,,)")|("(""parameter ACL"",,)")|NULL ("(""property graph element"",,,)")|("(""property graph element"",,)")|NULL ("(""property graph label"",,,)")|("(""property graph label"",,)")|NULL +("(""property graph element label"",,,)")|("(""property graph element label"",,)")|NULL ("(""property graph property"",,,)")|("(""property graph property"",,)")|NULL +("(""property graph label property"",,,)")|("(""property graph label property"",,)")|NULL -- restore normal output mode \a\t diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..9608dd5c4af 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -298,6 +298,29 @@ SELECT (pg_identify_object(classid, objid, objsubid)).* refobjid = 'create_property_graph_tests.g2'::regclass ORDER BY 1, 2, 3, 4; +-- test object address functions with recursive dependency walk +-- covers all property graph object types including indirect dependents +SELECT * +FROM ( + WITH RECURSIVE deps (classid, objid, objsubid, refclassid, refobjid, refobjsubid) AS ( + SELECT classid, objid, objsubid, + refclassid, refobjid, refobjsubid + FROM pg_depend + WHERE refclassid = 'pg_class'::regclass AND + refobjid = 'create_property_graph_tests.gt'::regclass + UNION ALL + SELECT d.classid, d.objid, d.objsubid, + d.refclassid, d.refobjid, d.refobjsubid + FROM pg_depend d + JOIN deps dp ON d.refclassid = dp.classid AND d.refobjid = dp.objid AND d.refobjsubid = dp.objsubid + ) + SELECT pg_describe_object(classid, objid, objsubid) as obj, + pg_identify_object(classid, objid, objsubid) as ident, + pg_identify_object_as_address(classid, objid, objsubid) as addr + FROM deps +) s +ORDER BY obj COLLATE "C", ident::text COLLATE "C"; + \a\t SELECT pg_get_propgraphdef('g2'::regclass); SELECT pg_get_propgraphdef('g3'::regclass); diff --git a/src/test/regress/sql/event_trigger.sql b/src/test/regress/sql/event_trigger.sql index 32e9bb58c5e..271f443378b 100644 --- a/src/test/regress/sql/event_trigger.sql +++ b/src/test/regress/sql/event_trigger.sql @@ -143,6 +143,19 @@ create user mapping for regress_evt_user server useless_server; alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +CREATE TABLE t2x (i int PRIMARY KEY, j text); + +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); + +DROP PROPERTY GRAPH gx; +DROP TABLE t1x, t2x; + -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; diff --git a/src/test/regress/sql/object_address.sql b/src/test/regress/sql/object_address.sql index 1bbe9457c1c..27109d421c7 100644 --- a/src/test/regress/sql/object_address.sql +++ b/src/test/regress/sql/object_address.sql @@ -67,7 +67,9 @@ DECLARE BEGIN FOR objtype IN VALUES ('toast table'), ('index column'), ('sequence column'), ('toast table column'), ('view column'), ('materialized view column'), - ('property graph element'), ('property graph label'), ('property graph property') + ('property graph element'), ('property graph element label'), + ('property graph label'), ('property graph label property'), + ('property graph property') LOOP BEGIN PERFORM pg_get_object_address(objtype, '{one}', '{}'); @@ -282,7 +284,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace -- 2.34.1 --R84XrR4Hgw0dH3Ec-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v2] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-23 09:27 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-23 09:27 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing them to hit the default case and error out with "unsupported object class". During DROP PROPERTY GRAPH, this manifests when an event trigger is active, because pg_event_trigger_ddl_commands() calls these functions. The same code paths are also reachable via pg_identify_object() and pg_identify_object_as_address(). This commit adds the missing cases. Test coverage is added in object_address.sql for these two catalog types via the zero-OID test that exercises pg_identify_object() and pg_identify_object_as_address(). A test in event_trigger.sql verifies that DROP PROPERTY GRAPH works correctly when an event trigger is active. Author: Bertrand Drouvot <[email protected]> Reviewed-by: Michael Paquier <[email protected]> Reviewed-by: Ashutosh Bapat <[email protected]> Discussion: https://postgr.es/m/aej1DkLwhyZWmtxJ@bdtpg --- src/backend/catalog/objectaddress.c | 93 ++++++++++++++++++++ src/test/regress/expected/event_trigger.out | 17 ++++ src/test/regress/expected/object_address.out | 4 + src/test/regress/sql/event_trigger.sql | 13 +++ src/test/regress/sql/object_address.sql | 2 + 5 files changed, 129 insertions(+) 62.4% src/backend/catalog/ 25.6% src/test/regress/expected/ 11.8% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/event_trigger.out b/src/test/regress/expected/event_trigger.out index 065f586310f..ed8d5df397e 100644 --- a/src/test/regress/expected/event_trigger.out +++ b/src/test/regress/expected/event_trigger.out @@ -173,6 +173,23 @@ NOTICE: test_event_trigger: ddl_command_end CREATE USER MAPPING alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; NOTICE: test_event_trigger: ddl_command_end ALTER DEFAULT PRIVILEGES +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE TABLE t2x (i int PRIMARY KEY, j text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); +NOTICE: test_event_trigger: ddl_command_end CREATE PROPERTY GRAPH +DROP PROPERTY GRAPH gx; +NOTICE: test_event_trigger: ddl_command_end DROP PROPERTY GRAPH +DROP TABLE t1x, t2x; +NOTICE: test_event_trigger: ddl_command_end DROP TABLE -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; ERROR: permission denied to change owner of event trigger "regress_event_trigger" diff --git a/src/test/regress/expected/object_address.out b/src/test/regress/expected/object_address.out index 97227d67a54..729c3537f25 100644 --- a/src/test/regress/expected/object_address.out +++ b/src/test/regress/expected/object_address.out @@ -593,7 +593,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace @@ -653,6 +655,8 @@ ORDER BY objects.classid, objects.objid, objects.objsubid; ("(""parameter ACL"",,,)")|("(""parameter ACL"",,)")|NULL ("(""property graph element"",,,)")|("(""property graph element"",,)")|NULL ("(""property graph label"",,,)")|("(""property graph label"",,)")|NULL +("(""property graph element label"",,,)")|("(""property graph element label"",,)")|NULL ("(""property graph property"",,,)")|("(""property graph property"",,)")|NULL +("(""property graph label property"",,,)")|("(""property graph label property"",,)")|NULL -- restore normal output mode \a\t diff --git a/src/test/regress/sql/event_trigger.sql b/src/test/regress/sql/event_trigger.sql index 32e9bb58c5e..271f443378b 100644 --- a/src/test/regress/sql/event_trigger.sql +++ b/src/test/regress/sql/event_trigger.sql @@ -143,6 +143,19 @@ create user mapping for regress_evt_user server useless_server; alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +CREATE TABLE t2x (i int PRIMARY KEY, j text); + +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); + +DROP PROPERTY GRAPH gx; +DROP TABLE t1x, t2x; + -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; diff --git a/src/test/regress/sql/object_address.sql b/src/test/regress/sql/object_address.sql index 1bbe9457c1c..620dacf1045 100644 --- a/src/test/regress/sql/object_address.sql +++ b/src/test/regress/sql/object_address.sql @@ -282,7 +282,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace -- 2.34.1 --gtUR827Uq8d5gVsQ-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v2] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-23 09:27 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-23 09:27 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing them to hit the default case and error out with "unsupported object class". During DROP PROPERTY GRAPH, this manifests when an event trigger is active, because pg_event_trigger_ddl_commands() calls these functions. The same code paths are also reachable via pg_identify_object() and pg_identify_object_as_address(). This commit adds the missing cases. Test coverage is added in object_address.sql for these two catalog types via the zero-OID test that exercises pg_identify_object() and pg_identify_object_as_address(). A test in event_trigger.sql verifies that DROP PROPERTY GRAPH works correctly when an event trigger is active. Author: Bertrand Drouvot <[email protected]> Reviewed-by: Michael Paquier <[email protected]> Reviewed-by: Ashutosh Bapat <[email protected]> Discussion: https://postgr.es/m/aej1DkLwhyZWmtxJ@bdtpg --- src/backend/catalog/objectaddress.c | 93 ++++++++++++++++++++ src/test/regress/expected/event_trigger.out | 17 ++++ src/test/regress/expected/object_address.out | 4 + src/test/regress/sql/event_trigger.sql | 13 +++ src/test/regress/sql/object_address.sql | 2 + 5 files changed, 129 insertions(+) 62.4% src/backend/catalog/ 25.6% src/test/regress/expected/ 11.8% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/event_trigger.out b/src/test/regress/expected/event_trigger.out index 065f586310f..ed8d5df397e 100644 --- a/src/test/regress/expected/event_trigger.out +++ b/src/test/regress/expected/event_trigger.out @@ -173,6 +173,23 @@ NOTICE: test_event_trigger: ddl_command_end CREATE USER MAPPING alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; NOTICE: test_event_trigger: ddl_command_end ALTER DEFAULT PRIVILEGES +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE TABLE t2x (i int PRIMARY KEY, j text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); +NOTICE: test_event_trigger: ddl_command_end CREATE PROPERTY GRAPH +DROP PROPERTY GRAPH gx; +NOTICE: test_event_trigger: ddl_command_end DROP PROPERTY GRAPH +DROP TABLE t1x, t2x; +NOTICE: test_event_trigger: ddl_command_end DROP TABLE -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; ERROR: permission denied to change owner of event trigger "regress_event_trigger" diff --git a/src/test/regress/expected/object_address.out b/src/test/regress/expected/object_address.out index 97227d67a54..729c3537f25 100644 --- a/src/test/regress/expected/object_address.out +++ b/src/test/regress/expected/object_address.out @@ -593,7 +593,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace @@ -653,6 +655,8 @@ ORDER BY objects.classid, objects.objid, objects.objsubid; ("(""parameter ACL"",,,)")|("(""parameter ACL"",,)")|NULL ("(""property graph element"",,,)")|("(""property graph element"",,)")|NULL ("(""property graph label"",,,)")|("(""property graph label"",,)")|NULL +("(""property graph element label"",,,)")|("(""property graph element label"",,)")|NULL ("(""property graph property"",,,)")|("(""property graph property"",,)")|NULL +("(""property graph label property"",,,)")|("(""property graph label property"",,)")|NULL -- restore normal output mode \a\t diff --git a/src/test/regress/sql/event_trigger.sql b/src/test/regress/sql/event_trigger.sql index 32e9bb58c5e..271f443378b 100644 --- a/src/test/regress/sql/event_trigger.sql +++ b/src/test/regress/sql/event_trigger.sql @@ -143,6 +143,19 @@ create user mapping for regress_evt_user server useless_server; alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +CREATE TABLE t2x (i int PRIMARY KEY, j text); + +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); + +DROP PROPERTY GRAPH gx; +DROP TABLE t1x, t2x; + -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; diff --git a/src/test/regress/sql/object_address.sql b/src/test/regress/sql/object_address.sql index 1bbe9457c1c..620dacf1045 100644 --- a/src/test/regress/sql/object_address.sql +++ b/src/test/regress/sql/object_address.sql @@ -282,7 +282,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace -- 2.34.1 --gtUR827Uq8d5gVsQ-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v2] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-23 09:27 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-23 09:27 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing them to hit the default case and error out with "unsupported object class". During DROP PROPERTY GRAPH, this manifests when an event trigger is active, because pg_event_trigger_ddl_commands() calls these functions. The same code paths are also reachable via pg_identify_object() and pg_identify_object_as_address(). This commit adds the missing cases. Test coverage is added in object_address.sql for these two catalog types via the zero-OID test that exercises pg_identify_object() and pg_identify_object_as_address(). A test in event_trigger.sql verifies that DROP PROPERTY GRAPH works correctly when an event trigger is active. Author: Bertrand Drouvot <[email protected]> Reviewed-by: Michael Paquier <[email protected]> Reviewed-by: Ashutosh Bapat <[email protected]> Discussion: https://postgr.es/m/aej1DkLwhyZWmtxJ@bdtpg --- src/backend/catalog/objectaddress.c | 93 ++++++++++++++++++++ src/test/regress/expected/event_trigger.out | 17 ++++ src/test/regress/expected/object_address.out | 4 + src/test/regress/sql/event_trigger.sql | 13 +++ src/test/regress/sql/object_address.sql | 2 + 5 files changed, 129 insertions(+) 62.4% src/backend/catalog/ 25.6% src/test/regress/expected/ 11.8% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/event_trigger.out b/src/test/regress/expected/event_trigger.out index 065f586310f..ed8d5df397e 100644 --- a/src/test/regress/expected/event_trigger.out +++ b/src/test/regress/expected/event_trigger.out @@ -173,6 +173,23 @@ NOTICE: test_event_trigger: ddl_command_end CREATE USER MAPPING alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; NOTICE: test_event_trigger: ddl_command_end ALTER DEFAULT PRIVILEGES +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE TABLE t2x (i int PRIMARY KEY, j text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); +NOTICE: test_event_trigger: ddl_command_end CREATE PROPERTY GRAPH +DROP PROPERTY GRAPH gx; +NOTICE: test_event_trigger: ddl_command_end DROP PROPERTY GRAPH +DROP TABLE t1x, t2x; +NOTICE: test_event_trigger: ddl_command_end DROP TABLE -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; ERROR: permission denied to change owner of event trigger "regress_event_trigger" diff --git a/src/test/regress/expected/object_address.out b/src/test/regress/expected/object_address.out index 97227d67a54..729c3537f25 100644 --- a/src/test/regress/expected/object_address.out +++ b/src/test/regress/expected/object_address.out @@ -593,7 +593,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace @@ -653,6 +655,8 @@ ORDER BY objects.classid, objects.objid, objects.objsubid; ("(""parameter ACL"",,,)")|("(""parameter ACL"",,)")|NULL ("(""property graph element"",,,)")|("(""property graph element"",,)")|NULL ("(""property graph label"",,,)")|("(""property graph label"",,)")|NULL +("(""property graph element label"",,,)")|("(""property graph element label"",,)")|NULL ("(""property graph property"",,,)")|("(""property graph property"",,)")|NULL +("(""property graph label property"",,,)")|("(""property graph label property"",,)")|NULL -- restore normal output mode \a\t diff --git a/src/test/regress/sql/event_trigger.sql b/src/test/regress/sql/event_trigger.sql index 32e9bb58c5e..271f443378b 100644 --- a/src/test/regress/sql/event_trigger.sql +++ b/src/test/regress/sql/event_trigger.sql @@ -143,6 +143,19 @@ create user mapping for regress_evt_user server useless_server; alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +CREATE TABLE t2x (i int PRIMARY KEY, j text); + +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); + +DROP PROPERTY GRAPH gx; +DROP TABLE t1x, t2x; + -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; diff --git a/src/test/regress/sql/object_address.sql b/src/test/regress/sql/object_address.sql index 1bbe9457c1c..620dacf1045 100644 --- a/src/test/regress/sql/object_address.sql +++ b/src/test/regress/sql/object_address.sql @@ -282,7 +282,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace -- 2.34.1 --gtUR827Uq8d5gVsQ-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v3] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-23 09:27 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-23 09:27 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing them to hit the default case and error out with "unsupported object class". During DROP PROPERTY GRAPH, this manifests when an event trigger is active, because pg_event_trigger_ddl_commands() calls these functions. The same code paths are also reachable via pg_identify_object() and pg_identify_object_as_address(). This commit adds the missing cases. Test coverage is added in object_address.sql for these two catalog types and in create_property_graph.sql covering all property graph object types. A test in event_trigger.sql verifies that DROP PROPERTY GRAPH works correctly when an event trigger is active. Author: Bertrand Drouvot <[email protected]> Reviewed-by: Michael Paquier <[email protected]> Reviewed-by: Ashutosh Bapat <[email protected]> Discussion: https://postgr.es/m/aej1DkLwhyZWmtxJ@bdtpg --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 78 ++++++++++++++++ src/test/regress/expected/event_trigger.out | 17 ++++ src/test/regress/expected/object_address.out | 10 +- .../regress/sql/create_property_graph.sql | 23 +++++ src/test/regress/sql/event_trigger.sql | 13 +++ src/test/regress/sql/object_address.sql | 6 +- 7 files changed, 238 insertions(+), 2 deletions(-) 14.7% src/backend/catalog/ 75.5% src/test/regress/expected/ 9.7% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..eb9e17fb727 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -752,6 +752,84 @@ SELECT (pg_identify_object(classid, objid, objsubid)).* type | create_property_graph_tests | g2 | create_property_graph_tests.g2 (21 rows) +-- test object address functions with recursive dependency walk +-- covers all property graph object types including indirect dependents +SELECT * +FROM ( + WITH RECURSIVE deps (classid, objid, objsubid, refclassid, refobjid, refobjsubid) AS ( + SELECT classid, objid, objsubid, + refclassid, refobjid, refobjsubid + FROM pg_depend + WHERE refclassid = 'pg_class'::regclass AND + refobjid = 'create_property_graph_tests.gt'::regclass + UNION ALL + SELECT d.classid, d.objid, d.objsubid, + d.refclassid, d.refobjid, d.refobjsubid + FROM pg_depend d + JOIN deps dp ON d.refclassid = dp.classid AND d.refobjid = dp.objid AND d.refobjsubid = dp.objsubid + ) + SELECT pg_describe_object(classid, objid, objsubid) as obj, + pg_identify_object(classid, objid, objsubid) as ident, + pg_identify_object_as_address(classid, objid, objsubid) as addr + FROM deps +) s +ORDER BY obj COLLATE "C", ident::text COLLATE "C"; + obj | ident | addr +----------------------------------------------------------+----------------------------------------------------------------------------+---------------------------------------------------------------------------- + edge e of property graph gt | ("property graph element",,,"e of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,e}",{}) + edge e of property graph gt | ("property graph element",,,"e of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,e}",{}) + edge e of property graph gt | ("property graph element",,,"e of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of property graph gt | ("property graph label",,,"e of create_property_graph_tests.gt") | ("property graph label","{create_property_graph_tests,gt,e}",{}) + label v1 of property graph gt | ("property graph label",,,"v1 of create_property_graph_tests.gt") | ("property graph label","{create_property_graph_tests,gt,v1}",{}) + label v1 of vertex v1 of property graph gt | ("property graph element label",,,"v1 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v1}",{}) + label v1 of vertex v1 of property graph gt | ("property graph element label",,,"v1 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v1}",{}) + label v2 of property graph gt | ("property graph label",,,"v2 of create_property_graph_tests.gt") | ("property graph label","{create_property_graph_tests,gt,v2}",{}) + label v2 of vertex v2 of property graph gt | ("property graph element label",,,"v2 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v2}",{}) + label v2 of vertex v2 of property graph gt | ("property graph element label",,,"v2 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v2}",{}) + property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property a of property graph gt | ("property graph property",,,"a of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,a}",{}) + property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property b of property graph gt | ("property graph property",,,"b of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,b}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of property graph gt | ("property graph property",,,"c of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,c}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of property graph gt | ("property graph property",,,"k1 of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,k1}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of property graph gt | ("property graph property",,,"k2 of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,k2}",{}) + property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property m of property graph gt | ("property graph property",,,"m of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,m}",{}) + property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property n of property graph gt | ("property graph property",,,"n of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,n}",{}) + type gt | (type,create_property_graph_tests,gt,create_property_graph_tests.gt) | (type,{create_property_graph_tests.gt},{}) + type gt[] | (type,create_property_graph_tests,_gt,create_property_graph_tests.gt[]) | (type,{create_property_graph_tests.gt[]},{}) + vertex v1 of property graph gt | ("property graph element",,,"v1 of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,v1}",{}) + vertex v2 of property graph gt | ("property graph element",,,"v2 of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,v2}",{}) +(52 rows) + \a\t SELECT pg_get_propgraphdef('g2'::regclass); CREATE PROPERTY GRAPH create_property_graph_tests.g2 diff --git a/src/test/regress/expected/event_trigger.out b/src/test/regress/expected/event_trigger.out index 065f586310f..ed8d5df397e 100644 --- a/src/test/regress/expected/event_trigger.out +++ b/src/test/regress/expected/event_trigger.out @@ -173,6 +173,23 @@ NOTICE: test_event_trigger: ddl_command_end CREATE USER MAPPING alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; NOTICE: test_event_trigger: ddl_command_end ALTER DEFAULT PRIVILEGES +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE TABLE t2x (i int PRIMARY KEY, j text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); +NOTICE: test_event_trigger: ddl_command_end CREATE PROPERTY GRAPH +DROP PROPERTY GRAPH gx; +NOTICE: test_event_trigger: ddl_command_end DROP PROPERTY GRAPH +DROP TABLE t1x, t2x; +NOTICE: test_event_trigger: ddl_command_end DROP TABLE -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; ERROR: permission denied to change owner of event trigger "regress_event_trigger" diff --git a/src/test/regress/expected/object_address.out b/src/test/regress/expected/object_address.out index 97227d67a54..5e53f0b092e 100644 --- a/src/test/regress/expected/object_address.out +++ b/src/test/regress/expected/object_address.out @@ -67,7 +67,9 @@ DECLARE BEGIN FOR objtype IN VALUES ('toast table'), ('index column'), ('sequence column'), ('toast table column'), ('view column'), ('materialized view column'), - ('property graph element'), ('property graph label'), ('property graph property') + ('property graph element'), ('property graph element label'), + ('property graph label'), ('property graph label property'), + ('property graph property') LOOP BEGIN PERFORM pg_get_object_address(objtype, '{one}', '{}'); @@ -84,7 +86,9 @@ WARNING: error for toast table column: unsupported object type "toast table col WARNING: error for view column: unsupported object type "view column" WARNING: error for materialized view column: unsupported object type "materialized view column" WARNING: error for property graph element: unsupported object type "property graph element" +WARNING: error for property graph element label: unrecognized object type "property graph element label" WARNING: error for property graph label: unsupported object type "property graph label" +WARNING: error for property graph label property: unrecognized object type "property graph label property" WARNING: error for property graph property: unsupported object type "property graph property" -- miscellaneous other errors select * from pg_get_object_address('operator of access method', '{btree,integer_ops,1}', '{int4,bool}'); @@ -593,7 +597,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace @@ -653,6 +659,8 @@ ORDER BY objects.classid, objects.objid, objects.objsubid; ("(""parameter ACL"",,,)")|("(""parameter ACL"",,)")|NULL ("(""property graph element"",,,)")|("(""property graph element"",,)")|NULL ("(""property graph label"",,,)")|("(""property graph label"",,)")|NULL +("(""property graph element label"",,,)")|("(""property graph element label"",,)")|NULL ("(""property graph property"",,,)")|("(""property graph property"",,)")|NULL +("(""property graph label property"",,,)")|("(""property graph label property"",,)")|NULL -- restore normal output mode \a\t diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..9608dd5c4af 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -298,6 +298,29 @@ SELECT (pg_identify_object(classid, objid, objsubid)).* refobjid = 'create_property_graph_tests.g2'::regclass ORDER BY 1, 2, 3, 4; +-- test object address functions with recursive dependency walk +-- covers all property graph object types including indirect dependents +SELECT * +FROM ( + WITH RECURSIVE deps (classid, objid, objsubid, refclassid, refobjid, refobjsubid) AS ( + SELECT classid, objid, objsubid, + refclassid, refobjid, refobjsubid + FROM pg_depend + WHERE refclassid = 'pg_class'::regclass AND + refobjid = 'create_property_graph_tests.gt'::regclass + UNION ALL + SELECT d.classid, d.objid, d.objsubid, + d.refclassid, d.refobjid, d.refobjsubid + FROM pg_depend d + JOIN deps dp ON d.refclassid = dp.classid AND d.refobjid = dp.objid AND d.refobjsubid = dp.objsubid + ) + SELECT pg_describe_object(classid, objid, objsubid) as obj, + pg_identify_object(classid, objid, objsubid) as ident, + pg_identify_object_as_address(classid, objid, objsubid) as addr + FROM deps +) s +ORDER BY obj COLLATE "C", ident::text COLLATE "C"; + \a\t SELECT pg_get_propgraphdef('g2'::regclass); SELECT pg_get_propgraphdef('g3'::regclass); diff --git a/src/test/regress/sql/event_trigger.sql b/src/test/regress/sql/event_trigger.sql index 32e9bb58c5e..271f443378b 100644 --- a/src/test/regress/sql/event_trigger.sql +++ b/src/test/regress/sql/event_trigger.sql @@ -143,6 +143,19 @@ create user mapping for regress_evt_user server useless_server; alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +CREATE TABLE t2x (i int PRIMARY KEY, j text); + +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); + +DROP PROPERTY GRAPH gx; +DROP TABLE t1x, t2x; + -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; diff --git a/src/test/regress/sql/object_address.sql b/src/test/regress/sql/object_address.sql index 1bbe9457c1c..27109d421c7 100644 --- a/src/test/regress/sql/object_address.sql +++ b/src/test/regress/sql/object_address.sql @@ -67,7 +67,9 @@ DECLARE BEGIN FOR objtype IN VALUES ('toast table'), ('index column'), ('sequence column'), ('toast table column'), ('view column'), ('materialized view column'), - ('property graph element'), ('property graph label'), ('property graph property') + ('property graph element'), ('property graph element label'), + ('property graph label'), ('property graph label property'), + ('property graph property') LOOP BEGIN PERFORM pg_get_object_address(objtype, '{one}', '{}'); @@ -282,7 +284,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace -- 2.34.1 --R84XrR4Hgw0dH3Ec-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v3] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-23 09:27 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-23 09:27 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing them to hit the default case and error out with "unsupported object class". During DROP PROPERTY GRAPH, this manifests when an event trigger is active, because pg_event_trigger_ddl_commands() calls these functions. The same code paths are also reachable via pg_identify_object() and pg_identify_object_as_address(). This commit adds the missing cases. Test coverage is added in object_address.sql for these two catalog types and in create_property_graph.sql covering all property graph object types. A test in event_trigger.sql verifies that DROP PROPERTY GRAPH works correctly when an event trigger is active. Author: Bertrand Drouvot <[email protected]> Reviewed-by: Michael Paquier <[email protected]> Reviewed-by: Ashutosh Bapat <[email protected]> Discussion: https://postgr.es/m/aej1DkLwhyZWmtxJ@bdtpg --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 78 ++++++++++++++++ src/test/regress/expected/event_trigger.out | 17 ++++ src/test/regress/expected/object_address.out | 10 +- .../regress/sql/create_property_graph.sql | 23 +++++ src/test/regress/sql/event_trigger.sql | 13 +++ src/test/regress/sql/object_address.sql | 6 +- 7 files changed, 238 insertions(+), 2 deletions(-) 14.7% src/backend/catalog/ 75.5% src/test/regress/expected/ 9.7% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..eb9e17fb727 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -752,6 +752,84 @@ SELECT (pg_identify_object(classid, objid, objsubid)).* type | create_property_graph_tests | g2 | create_property_graph_tests.g2 (21 rows) +-- test object address functions with recursive dependency walk +-- covers all property graph object types including indirect dependents +SELECT * +FROM ( + WITH RECURSIVE deps (classid, objid, objsubid, refclassid, refobjid, refobjsubid) AS ( + SELECT classid, objid, objsubid, + refclassid, refobjid, refobjsubid + FROM pg_depend + WHERE refclassid = 'pg_class'::regclass AND + refobjid = 'create_property_graph_tests.gt'::regclass + UNION ALL + SELECT d.classid, d.objid, d.objsubid, + d.refclassid, d.refobjid, d.refobjsubid + FROM pg_depend d + JOIN deps dp ON d.refclassid = dp.classid AND d.refobjid = dp.objid AND d.refobjsubid = dp.objsubid + ) + SELECT pg_describe_object(classid, objid, objsubid) as obj, + pg_identify_object(classid, objid, objsubid) as ident, + pg_identify_object_as_address(classid, objid, objsubid) as addr + FROM deps +) s +ORDER BY obj COLLATE "C", ident::text COLLATE "C"; + obj | ident | addr +----------------------------------------------------------+----------------------------------------------------------------------------+---------------------------------------------------------------------------- + edge e of property graph gt | ("property graph element",,,"e of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,e}",{}) + edge e of property graph gt | ("property graph element",,,"e of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,e}",{}) + edge e of property graph gt | ("property graph element",,,"e of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of property graph gt | ("property graph label",,,"e of create_property_graph_tests.gt") | ("property graph label","{create_property_graph_tests,gt,e}",{}) + label v1 of property graph gt | ("property graph label",,,"v1 of create_property_graph_tests.gt") | ("property graph label","{create_property_graph_tests,gt,v1}",{}) + label v1 of vertex v1 of property graph gt | ("property graph element label",,,"v1 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v1}",{}) + label v1 of vertex v1 of property graph gt | ("property graph element label",,,"v1 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v1}",{}) + label v2 of property graph gt | ("property graph label",,,"v2 of create_property_graph_tests.gt") | ("property graph label","{create_property_graph_tests,gt,v2}",{}) + label v2 of vertex v2 of property graph gt | ("property graph element label",,,"v2 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v2}",{}) + label v2 of vertex v2 of property graph gt | ("property graph element label",,,"v2 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v2}",{}) + property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property a of property graph gt | ("property graph property",,,"a of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,a}",{}) + property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property b of property graph gt | ("property graph property",,,"b of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,b}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of property graph gt | ("property graph property",,,"c of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,c}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of property graph gt | ("property graph property",,,"k1 of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,k1}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of property graph gt | ("property graph property",,,"k2 of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,k2}",{}) + property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property m of property graph gt | ("property graph property",,,"m of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,m}",{}) + property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property n of property graph gt | ("property graph property",,,"n of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,n}",{}) + type gt | (type,create_property_graph_tests,gt,create_property_graph_tests.gt) | (type,{create_property_graph_tests.gt},{}) + type gt[] | (type,create_property_graph_tests,_gt,create_property_graph_tests.gt[]) | (type,{create_property_graph_tests.gt[]},{}) + vertex v1 of property graph gt | ("property graph element",,,"v1 of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,v1}",{}) + vertex v2 of property graph gt | ("property graph element",,,"v2 of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,v2}",{}) +(52 rows) + \a\t SELECT pg_get_propgraphdef('g2'::regclass); CREATE PROPERTY GRAPH create_property_graph_tests.g2 diff --git a/src/test/regress/expected/event_trigger.out b/src/test/regress/expected/event_trigger.out index 065f586310f..ed8d5df397e 100644 --- a/src/test/regress/expected/event_trigger.out +++ b/src/test/regress/expected/event_trigger.out @@ -173,6 +173,23 @@ NOTICE: test_event_trigger: ddl_command_end CREATE USER MAPPING alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; NOTICE: test_event_trigger: ddl_command_end ALTER DEFAULT PRIVILEGES +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE TABLE t2x (i int PRIMARY KEY, j text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); +NOTICE: test_event_trigger: ddl_command_end CREATE PROPERTY GRAPH +DROP PROPERTY GRAPH gx; +NOTICE: test_event_trigger: ddl_command_end DROP PROPERTY GRAPH +DROP TABLE t1x, t2x; +NOTICE: test_event_trigger: ddl_command_end DROP TABLE -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; ERROR: permission denied to change owner of event trigger "regress_event_trigger" diff --git a/src/test/regress/expected/object_address.out b/src/test/regress/expected/object_address.out index 97227d67a54..5e53f0b092e 100644 --- a/src/test/regress/expected/object_address.out +++ b/src/test/regress/expected/object_address.out @@ -67,7 +67,9 @@ DECLARE BEGIN FOR objtype IN VALUES ('toast table'), ('index column'), ('sequence column'), ('toast table column'), ('view column'), ('materialized view column'), - ('property graph element'), ('property graph label'), ('property graph property') + ('property graph element'), ('property graph element label'), + ('property graph label'), ('property graph label property'), + ('property graph property') LOOP BEGIN PERFORM pg_get_object_address(objtype, '{one}', '{}'); @@ -84,7 +86,9 @@ WARNING: error for toast table column: unsupported object type "toast table col WARNING: error for view column: unsupported object type "view column" WARNING: error for materialized view column: unsupported object type "materialized view column" WARNING: error for property graph element: unsupported object type "property graph element" +WARNING: error for property graph element label: unrecognized object type "property graph element label" WARNING: error for property graph label: unsupported object type "property graph label" +WARNING: error for property graph label property: unrecognized object type "property graph label property" WARNING: error for property graph property: unsupported object type "property graph property" -- miscellaneous other errors select * from pg_get_object_address('operator of access method', '{btree,integer_ops,1}', '{int4,bool}'); @@ -593,7 +597,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace @@ -653,6 +659,8 @@ ORDER BY objects.classid, objects.objid, objects.objsubid; ("(""parameter ACL"",,,)")|("(""parameter ACL"",,)")|NULL ("(""property graph element"",,,)")|("(""property graph element"",,)")|NULL ("(""property graph label"",,,)")|("(""property graph label"",,)")|NULL +("(""property graph element label"",,,)")|("(""property graph element label"",,)")|NULL ("(""property graph property"",,,)")|("(""property graph property"",,)")|NULL +("(""property graph label property"",,,)")|("(""property graph label property"",,)")|NULL -- restore normal output mode \a\t diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..9608dd5c4af 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -298,6 +298,29 @@ SELECT (pg_identify_object(classid, objid, objsubid)).* refobjid = 'create_property_graph_tests.g2'::regclass ORDER BY 1, 2, 3, 4; +-- test object address functions with recursive dependency walk +-- covers all property graph object types including indirect dependents +SELECT * +FROM ( + WITH RECURSIVE deps (classid, objid, objsubid, refclassid, refobjid, refobjsubid) AS ( + SELECT classid, objid, objsubid, + refclassid, refobjid, refobjsubid + FROM pg_depend + WHERE refclassid = 'pg_class'::regclass AND + refobjid = 'create_property_graph_tests.gt'::regclass + UNION ALL + SELECT d.classid, d.objid, d.objsubid, + d.refclassid, d.refobjid, d.refobjsubid + FROM pg_depend d + JOIN deps dp ON d.refclassid = dp.classid AND d.refobjid = dp.objid AND d.refobjsubid = dp.objsubid + ) + SELECT pg_describe_object(classid, objid, objsubid) as obj, + pg_identify_object(classid, objid, objsubid) as ident, + pg_identify_object_as_address(classid, objid, objsubid) as addr + FROM deps +) s +ORDER BY obj COLLATE "C", ident::text COLLATE "C"; + \a\t SELECT pg_get_propgraphdef('g2'::regclass); SELECT pg_get_propgraphdef('g3'::regclass); diff --git a/src/test/regress/sql/event_trigger.sql b/src/test/regress/sql/event_trigger.sql index 32e9bb58c5e..271f443378b 100644 --- a/src/test/regress/sql/event_trigger.sql +++ b/src/test/regress/sql/event_trigger.sql @@ -143,6 +143,19 @@ create user mapping for regress_evt_user server useless_server; alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +CREATE TABLE t2x (i int PRIMARY KEY, j text); + +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); + +DROP PROPERTY GRAPH gx; +DROP TABLE t1x, t2x; + -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; diff --git a/src/test/regress/sql/object_address.sql b/src/test/regress/sql/object_address.sql index 1bbe9457c1c..27109d421c7 100644 --- a/src/test/regress/sql/object_address.sql +++ b/src/test/regress/sql/object_address.sql @@ -67,7 +67,9 @@ DECLARE BEGIN FOR objtype IN VALUES ('toast table'), ('index column'), ('sequence column'), ('toast table column'), ('view column'), ('materialized view column'), - ('property graph element'), ('property graph label'), ('property graph property') + ('property graph element'), ('property graph element label'), + ('property graph label'), ('property graph label property'), + ('property graph property') LOOP BEGIN PERFORM pg_get_object_address(objtype, '{one}', '{}'); @@ -282,7 +284,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace -- 2.34.1 --R84XrR4Hgw0dH3Ec-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v2] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-23 09:27 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-23 09:27 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing them to hit the default case and error out with "unsupported object class". During DROP PROPERTY GRAPH, this manifests when an event trigger is active, because pg_event_trigger_ddl_commands() calls these functions. The same code paths are also reachable via pg_identify_object() and pg_identify_object_as_address(). This commit adds the missing cases. Test coverage is added in object_address.sql for these two catalog types via the zero-OID test that exercises pg_identify_object() and pg_identify_object_as_address(). A test in event_trigger.sql verifies that DROP PROPERTY GRAPH works correctly when an event trigger is active. Author: Bertrand Drouvot <[email protected]> Reviewed-by: Michael Paquier <[email protected]> Reviewed-by: Ashutosh Bapat <[email protected]> Discussion: https://postgr.es/m/aej1DkLwhyZWmtxJ@bdtpg --- src/backend/catalog/objectaddress.c | 93 ++++++++++++++++++++ src/test/regress/expected/event_trigger.out | 17 ++++ src/test/regress/expected/object_address.out | 4 + src/test/regress/sql/event_trigger.sql | 13 +++ src/test/regress/sql/object_address.sql | 2 + 5 files changed, 129 insertions(+) 62.4% src/backend/catalog/ 25.6% src/test/regress/expected/ 11.8% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/event_trigger.out b/src/test/regress/expected/event_trigger.out index 065f586310f..ed8d5df397e 100644 --- a/src/test/regress/expected/event_trigger.out +++ b/src/test/regress/expected/event_trigger.out @@ -173,6 +173,23 @@ NOTICE: test_event_trigger: ddl_command_end CREATE USER MAPPING alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; NOTICE: test_event_trigger: ddl_command_end ALTER DEFAULT PRIVILEGES +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE TABLE t2x (i int PRIMARY KEY, j text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); +NOTICE: test_event_trigger: ddl_command_end CREATE PROPERTY GRAPH +DROP PROPERTY GRAPH gx; +NOTICE: test_event_trigger: ddl_command_end DROP PROPERTY GRAPH +DROP TABLE t1x, t2x; +NOTICE: test_event_trigger: ddl_command_end DROP TABLE -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; ERROR: permission denied to change owner of event trigger "regress_event_trigger" diff --git a/src/test/regress/expected/object_address.out b/src/test/regress/expected/object_address.out index 97227d67a54..729c3537f25 100644 --- a/src/test/regress/expected/object_address.out +++ b/src/test/regress/expected/object_address.out @@ -593,7 +593,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace @@ -653,6 +655,8 @@ ORDER BY objects.classid, objects.objid, objects.objsubid; ("(""parameter ACL"",,,)")|("(""parameter ACL"",,)")|NULL ("(""property graph element"",,,)")|("(""property graph element"",,)")|NULL ("(""property graph label"",,,)")|("(""property graph label"",,)")|NULL +("(""property graph element label"",,,)")|("(""property graph element label"",,)")|NULL ("(""property graph property"",,,)")|("(""property graph property"",,)")|NULL +("(""property graph label property"",,,)")|("(""property graph label property"",,)")|NULL -- restore normal output mode \a\t diff --git a/src/test/regress/sql/event_trigger.sql b/src/test/regress/sql/event_trigger.sql index 32e9bb58c5e..271f443378b 100644 --- a/src/test/regress/sql/event_trigger.sql +++ b/src/test/regress/sql/event_trigger.sql @@ -143,6 +143,19 @@ create user mapping for regress_evt_user server useless_server; alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +CREATE TABLE t2x (i int PRIMARY KEY, j text); + +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); + +DROP PROPERTY GRAPH gx; +DROP TABLE t1x, t2x; + -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; diff --git a/src/test/regress/sql/object_address.sql b/src/test/regress/sql/object_address.sql index 1bbe9457c1c..620dacf1045 100644 --- a/src/test/regress/sql/object_address.sql +++ b/src/test/regress/sql/object_address.sql @@ -282,7 +282,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace -- 2.34.1 --gtUR827Uq8d5gVsQ-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v2] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-23 09:27 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-23 09:27 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing them to hit the default case and error out with "unsupported object class". During DROP PROPERTY GRAPH, this manifests when an event trigger is active, because pg_event_trigger_ddl_commands() calls these functions. The same code paths are also reachable via pg_identify_object() and pg_identify_object_as_address(). This commit adds the missing cases. Test coverage is added in object_address.sql for these two catalog types via the zero-OID test that exercises pg_identify_object() and pg_identify_object_as_address(). A test in event_trigger.sql verifies that DROP PROPERTY GRAPH works correctly when an event trigger is active. Author: Bertrand Drouvot <[email protected]> Reviewed-by: Michael Paquier <[email protected]> Reviewed-by: Ashutosh Bapat <[email protected]> Discussion: https://postgr.es/m/aej1DkLwhyZWmtxJ@bdtpg --- src/backend/catalog/objectaddress.c | 93 ++++++++++++++++++++ src/test/regress/expected/event_trigger.out | 17 ++++ src/test/regress/expected/object_address.out | 4 + src/test/regress/sql/event_trigger.sql | 13 +++ src/test/regress/sql/object_address.sql | 2 + 5 files changed, 129 insertions(+) 62.4% src/backend/catalog/ 25.6% src/test/regress/expected/ 11.8% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/event_trigger.out b/src/test/regress/expected/event_trigger.out index 065f586310f..ed8d5df397e 100644 --- a/src/test/regress/expected/event_trigger.out +++ b/src/test/regress/expected/event_trigger.out @@ -173,6 +173,23 @@ NOTICE: test_event_trigger: ddl_command_end CREATE USER MAPPING alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; NOTICE: test_event_trigger: ddl_command_end ALTER DEFAULT PRIVILEGES +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE TABLE t2x (i int PRIMARY KEY, j text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); +NOTICE: test_event_trigger: ddl_command_end CREATE PROPERTY GRAPH +DROP PROPERTY GRAPH gx; +NOTICE: test_event_trigger: ddl_command_end DROP PROPERTY GRAPH +DROP TABLE t1x, t2x; +NOTICE: test_event_trigger: ddl_command_end DROP TABLE -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; ERROR: permission denied to change owner of event trigger "regress_event_trigger" diff --git a/src/test/regress/expected/object_address.out b/src/test/regress/expected/object_address.out index 97227d67a54..729c3537f25 100644 --- a/src/test/regress/expected/object_address.out +++ b/src/test/regress/expected/object_address.out @@ -593,7 +593,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace @@ -653,6 +655,8 @@ ORDER BY objects.classid, objects.objid, objects.objsubid; ("(""parameter ACL"",,,)")|("(""parameter ACL"",,)")|NULL ("(""property graph element"",,,)")|("(""property graph element"",,)")|NULL ("(""property graph label"",,,)")|("(""property graph label"",,)")|NULL +("(""property graph element label"",,,)")|("(""property graph element label"",,)")|NULL ("(""property graph property"",,,)")|("(""property graph property"",,)")|NULL +("(""property graph label property"",,,)")|("(""property graph label property"",,)")|NULL -- restore normal output mode \a\t diff --git a/src/test/regress/sql/event_trigger.sql b/src/test/regress/sql/event_trigger.sql index 32e9bb58c5e..271f443378b 100644 --- a/src/test/regress/sql/event_trigger.sql +++ b/src/test/regress/sql/event_trigger.sql @@ -143,6 +143,19 @@ create user mapping for regress_evt_user server useless_server; alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +CREATE TABLE t2x (i int PRIMARY KEY, j text); + +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); + +DROP PROPERTY GRAPH gx; +DROP TABLE t1x, t2x; + -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; diff --git a/src/test/regress/sql/object_address.sql b/src/test/regress/sql/object_address.sql index 1bbe9457c1c..620dacf1045 100644 --- a/src/test/regress/sql/object_address.sql +++ b/src/test/regress/sql/object_address.sql @@ -282,7 +282,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace -- 2.34.1 --gtUR827Uq8d5gVsQ-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v2] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-23 09:27 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-23 09:27 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing them to hit the default case and error out with "unsupported object class". During DROP PROPERTY GRAPH, this manifests when an event trigger is active, because pg_event_trigger_ddl_commands() calls these functions. The same code paths are also reachable via pg_identify_object() and pg_identify_object_as_address(). This commit adds the missing cases. Test coverage is added in object_address.sql for these two catalog types via the zero-OID test that exercises pg_identify_object() and pg_identify_object_as_address(). A test in event_trigger.sql verifies that DROP PROPERTY GRAPH works correctly when an event trigger is active. Author: Bertrand Drouvot <[email protected]> Reviewed-by: Michael Paquier <[email protected]> Reviewed-by: Ashutosh Bapat <[email protected]> Discussion: https://postgr.es/m/aej1DkLwhyZWmtxJ@bdtpg --- src/backend/catalog/objectaddress.c | 93 ++++++++++++++++++++ src/test/regress/expected/event_trigger.out | 17 ++++ src/test/regress/expected/object_address.out | 4 + src/test/regress/sql/event_trigger.sql | 13 +++ src/test/regress/sql/object_address.sql | 2 + 5 files changed, 129 insertions(+) 62.4% src/backend/catalog/ 25.6% src/test/regress/expected/ 11.8% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/event_trigger.out b/src/test/regress/expected/event_trigger.out index 065f586310f..ed8d5df397e 100644 --- a/src/test/regress/expected/event_trigger.out +++ b/src/test/regress/expected/event_trigger.out @@ -173,6 +173,23 @@ NOTICE: test_event_trigger: ddl_command_end CREATE USER MAPPING alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; NOTICE: test_event_trigger: ddl_command_end ALTER DEFAULT PRIVILEGES +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE TABLE t2x (i int PRIMARY KEY, j text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); +NOTICE: test_event_trigger: ddl_command_end CREATE PROPERTY GRAPH +DROP PROPERTY GRAPH gx; +NOTICE: test_event_trigger: ddl_command_end DROP PROPERTY GRAPH +DROP TABLE t1x, t2x; +NOTICE: test_event_trigger: ddl_command_end DROP TABLE -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; ERROR: permission denied to change owner of event trigger "regress_event_trigger" diff --git a/src/test/regress/expected/object_address.out b/src/test/regress/expected/object_address.out index 97227d67a54..729c3537f25 100644 --- a/src/test/regress/expected/object_address.out +++ b/src/test/regress/expected/object_address.out @@ -593,7 +593,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace @@ -653,6 +655,8 @@ ORDER BY objects.classid, objects.objid, objects.objsubid; ("(""parameter ACL"",,,)")|("(""parameter ACL"",,)")|NULL ("(""property graph element"",,,)")|("(""property graph element"",,)")|NULL ("(""property graph label"",,,)")|("(""property graph label"",,)")|NULL +("(""property graph element label"",,,)")|("(""property graph element label"",,)")|NULL ("(""property graph property"",,,)")|("(""property graph property"",,)")|NULL +("(""property graph label property"",,,)")|("(""property graph label property"",,)")|NULL -- restore normal output mode \a\t diff --git a/src/test/regress/sql/event_trigger.sql b/src/test/regress/sql/event_trigger.sql index 32e9bb58c5e..271f443378b 100644 --- a/src/test/regress/sql/event_trigger.sql +++ b/src/test/regress/sql/event_trigger.sql @@ -143,6 +143,19 @@ create user mapping for regress_evt_user server useless_server; alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +CREATE TABLE t2x (i int PRIMARY KEY, j text); + +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); + +DROP PROPERTY GRAPH gx; +DROP TABLE t1x, t2x; + -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; diff --git a/src/test/regress/sql/object_address.sql b/src/test/regress/sql/object_address.sql index 1bbe9457c1c..620dacf1045 100644 --- a/src/test/regress/sql/object_address.sql +++ b/src/test/regress/sql/object_address.sql @@ -282,7 +282,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace -- 2.34.1 --gtUR827Uq8d5gVsQ-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v3] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-23 09:27 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-23 09:27 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing them to hit the default case and error out with "unsupported object class". During DROP PROPERTY GRAPH, this manifests when an event trigger is active, because pg_event_trigger_ddl_commands() calls these functions. The same code paths are also reachable via pg_identify_object() and pg_identify_object_as_address(). This commit adds the missing cases. Test coverage is added in object_address.sql for these two catalog types and in create_property_graph.sql covering all property graph object types. A test in event_trigger.sql verifies that DROP PROPERTY GRAPH works correctly when an event trigger is active. Author: Bertrand Drouvot <[email protected]> Reviewed-by: Michael Paquier <[email protected]> Reviewed-by: Ashutosh Bapat <[email protected]> Discussion: https://postgr.es/m/aej1DkLwhyZWmtxJ@bdtpg --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 78 ++++++++++++++++ src/test/regress/expected/event_trigger.out | 17 ++++ src/test/regress/expected/object_address.out | 10 +- .../regress/sql/create_property_graph.sql | 23 +++++ src/test/regress/sql/event_trigger.sql | 13 +++ src/test/regress/sql/object_address.sql | 6 +- 7 files changed, 238 insertions(+), 2 deletions(-) 14.7% src/backend/catalog/ 75.5% src/test/regress/expected/ 9.7% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..eb9e17fb727 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -752,6 +752,84 @@ SELECT (pg_identify_object(classid, objid, objsubid)).* type | create_property_graph_tests | g2 | create_property_graph_tests.g2 (21 rows) +-- test object address functions with recursive dependency walk +-- covers all property graph object types including indirect dependents +SELECT * +FROM ( + WITH RECURSIVE deps (classid, objid, objsubid, refclassid, refobjid, refobjsubid) AS ( + SELECT classid, objid, objsubid, + refclassid, refobjid, refobjsubid + FROM pg_depend + WHERE refclassid = 'pg_class'::regclass AND + refobjid = 'create_property_graph_tests.gt'::regclass + UNION ALL + SELECT d.classid, d.objid, d.objsubid, + d.refclassid, d.refobjid, d.refobjsubid + FROM pg_depend d + JOIN deps dp ON d.refclassid = dp.classid AND d.refobjid = dp.objid AND d.refobjsubid = dp.objsubid + ) + SELECT pg_describe_object(classid, objid, objsubid) as obj, + pg_identify_object(classid, objid, objsubid) as ident, + pg_identify_object_as_address(classid, objid, objsubid) as addr + FROM deps +) s +ORDER BY obj COLLATE "C", ident::text COLLATE "C"; + obj | ident | addr +----------------------------------------------------------+----------------------------------------------------------------------------+---------------------------------------------------------------------------- + edge e of property graph gt | ("property graph element",,,"e of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,e}",{}) + edge e of property graph gt | ("property graph element",,,"e of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,e}",{}) + edge e of property graph gt | ("property graph element",,,"e of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of property graph gt | ("property graph label",,,"e of create_property_graph_tests.gt") | ("property graph label","{create_property_graph_tests,gt,e}",{}) + label v1 of property graph gt | ("property graph label",,,"v1 of create_property_graph_tests.gt") | ("property graph label","{create_property_graph_tests,gt,v1}",{}) + label v1 of vertex v1 of property graph gt | ("property graph element label",,,"v1 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v1}",{}) + label v1 of vertex v1 of property graph gt | ("property graph element label",,,"v1 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v1}",{}) + label v2 of property graph gt | ("property graph label",,,"v2 of create_property_graph_tests.gt") | ("property graph label","{create_property_graph_tests,gt,v2}",{}) + label v2 of vertex v2 of property graph gt | ("property graph element label",,,"v2 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v2}",{}) + label v2 of vertex v2 of property graph gt | ("property graph element label",,,"v2 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v2}",{}) + property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property a of property graph gt | ("property graph property",,,"a of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,a}",{}) + property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property b of property graph gt | ("property graph property",,,"b of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,b}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of property graph gt | ("property graph property",,,"c of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,c}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of property graph gt | ("property graph property",,,"k1 of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,k1}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of property graph gt | ("property graph property",,,"k2 of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,k2}",{}) + property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property m of property graph gt | ("property graph property",,,"m of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,m}",{}) + property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property n of property graph gt | ("property graph property",,,"n of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,n}",{}) + type gt | (type,create_property_graph_tests,gt,create_property_graph_tests.gt) | (type,{create_property_graph_tests.gt},{}) + type gt[] | (type,create_property_graph_tests,_gt,create_property_graph_tests.gt[]) | (type,{create_property_graph_tests.gt[]},{}) + vertex v1 of property graph gt | ("property graph element",,,"v1 of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,v1}",{}) + vertex v2 of property graph gt | ("property graph element",,,"v2 of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,v2}",{}) +(52 rows) + \a\t SELECT pg_get_propgraphdef('g2'::regclass); CREATE PROPERTY GRAPH create_property_graph_tests.g2 diff --git a/src/test/regress/expected/event_trigger.out b/src/test/regress/expected/event_trigger.out index 065f586310f..ed8d5df397e 100644 --- a/src/test/regress/expected/event_trigger.out +++ b/src/test/regress/expected/event_trigger.out @@ -173,6 +173,23 @@ NOTICE: test_event_trigger: ddl_command_end CREATE USER MAPPING alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; NOTICE: test_event_trigger: ddl_command_end ALTER DEFAULT PRIVILEGES +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE TABLE t2x (i int PRIMARY KEY, j text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); +NOTICE: test_event_trigger: ddl_command_end CREATE PROPERTY GRAPH +DROP PROPERTY GRAPH gx; +NOTICE: test_event_trigger: ddl_command_end DROP PROPERTY GRAPH +DROP TABLE t1x, t2x; +NOTICE: test_event_trigger: ddl_command_end DROP TABLE -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; ERROR: permission denied to change owner of event trigger "regress_event_trigger" diff --git a/src/test/regress/expected/object_address.out b/src/test/regress/expected/object_address.out index 97227d67a54..5e53f0b092e 100644 --- a/src/test/regress/expected/object_address.out +++ b/src/test/regress/expected/object_address.out @@ -67,7 +67,9 @@ DECLARE BEGIN FOR objtype IN VALUES ('toast table'), ('index column'), ('sequence column'), ('toast table column'), ('view column'), ('materialized view column'), - ('property graph element'), ('property graph label'), ('property graph property') + ('property graph element'), ('property graph element label'), + ('property graph label'), ('property graph label property'), + ('property graph property') LOOP BEGIN PERFORM pg_get_object_address(objtype, '{one}', '{}'); @@ -84,7 +86,9 @@ WARNING: error for toast table column: unsupported object type "toast table col WARNING: error for view column: unsupported object type "view column" WARNING: error for materialized view column: unsupported object type "materialized view column" WARNING: error for property graph element: unsupported object type "property graph element" +WARNING: error for property graph element label: unrecognized object type "property graph element label" WARNING: error for property graph label: unsupported object type "property graph label" +WARNING: error for property graph label property: unrecognized object type "property graph label property" WARNING: error for property graph property: unsupported object type "property graph property" -- miscellaneous other errors select * from pg_get_object_address('operator of access method', '{btree,integer_ops,1}', '{int4,bool}'); @@ -593,7 +597,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace @@ -653,6 +659,8 @@ ORDER BY objects.classid, objects.objid, objects.objsubid; ("(""parameter ACL"",,,)")|("(""parameter ACL"",,)")|NULL ("(""property graph element"",,,)")|("(""property graph element"",,)")|NULL ("(""property graph label"",,,)")|("(""property graph label"",,)")|NULL +("(""property graph element label"",,,)")|("(""property graph element label"",,)")|NULL ("(""property graph property"",,,)")|("(""property graph property"",,)")|NULL +("(""property graph label property"",,,)")|("(""property graph label property"",,)")|NULL -- restore normal output mode \a\t diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..9608dd5c4af 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -298,6 +298,29 @@ SELECT (pg_identify_object(classid, objid, objsubid)).* refobjid = 'create_property_graph_tests.g2'::regclass ORDER BY 1, 2, 3, 4; +-- test object address functions with recursive dependency walk +-- covers all property graph object types including indirect dependents +SELECT * +FROM ( + WITH RECURSIVE deps (classid, objid, objsubid, refclassid, refobjid, refobjsubid) AS ( + SELECT classid, objid, objsubid, + refclassid, refobjid, refobjsubid + FROM pg_depend + WHERE refclassid = 'pg_class'::regclass AND + refobjid = 'create_property_graph_tests.gt'::regclass + UNION ALL + SELECT d.classid, d.objid, d.objsubid, + d.refclassid, d.refobjid, d.refobjsubid + FROM pg_depend d + JOIN deps dp ON d.refclassid = dp.classid AND d.refobjid = dp.objid AND d.refobjsubid = dp.objsubid + ) + SELECT pg_describe_object(classid, objid, objsubid) as obj, + pg_identify_object(classid, objid, objsubid) as ident, + pg_identify_object_as_address(classid, objid, objsubid) as addr + FROM deps +) s +ORDER BY obj COLLATE "C", ident::text COLLATE "C"; + \a\t SELECT pg_get_propgraphdef('g2'::regclass); SELECT pg_get_propgraphdef('g3'::regclass); diff --git a/src/test/regress/sql/event_trigger.sql b/src/test/regress/sql/event_trigger.sql index 32e9bb58c5e..271f443378b 100644 --- a/src/test/regress/sql/event_trigger.sql +++ b/src/test/regress/sql/event_trigger.sql @@ -143,6 +143,19 @@ create user mapping for regress_evt_user server useless_server; alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +CREATE TABLE t2x (i int PRIMARY KEY, j text); + +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); + +DROP PROPERTY GRAPH gx; +DROP TABLE t1x, t2x; + -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; diff --git a/src/test/regress/sql/object_address.sql b/src/test/regress/sql/object_address.sql index 1bbe9457c1c..27109d421c7 100644 --- a/src/test/regress/sql/object_address.sql +++ b/src/test/regress/sql/object_address.sql @@ -67,7 +67,9 @@ DECLARE BEGIN FOR objtype IN VALUES ('toast table'), ('index column'), ('sequence column'), ('toast table column'), ('view column'), ('materialized view column'), - ('property graph element'), ('property graph label'), ('property graph property') + ('property graph element'), ('property graph element label'), + ('property graph label'), ('property graph label property'), + ('property graph property') LOOP BEGIN PERFORM pg_get_object_address(objtype, '{one}', '{}'); @@ -282,7 +284,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace -- 2.34.1 --R84XrR4Hgw0dH3Ec-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v3] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-23 09:27 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-23 09:27 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing them to hit the default case and error out with "unsupported object class". During DROP PROPERTY GRAPH, this manifests when an event trigger is active, because pg_event_trigger_ddl_commands() calls these functions. The same code paths are also reachable via pg_identify_object() and pg_identify_object_as_address(). This commit adds the missing cases. Test coverage is added in object_address.sql for these two catalog types and in create_property_graph.sql covering all property graph object types. A test in event_trigger.sql verifies that DROP PROPERTY GRAPH works correctly when an event trigger is active. Author: Bertrand Drouvot <[email protected]> Reviewed-by: Michael Paquier <[email protected]> Reviewed-by: Ashutosh Bapat <[email protected]> Discussion: https://postgr.es/m/aej1DkLwhyZWmtxJ@bdtpg --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 78 ++++++++++++++++ src/test/regress/expected/event_trigger.out | 17 ++++ src/test/regress/expected/object_address.out | 10 +- .../regress/sql/create_property_graph.sql | 23 +++++ src/test/regress/sql/event_trigger.sql | 13 +++ src/test/regress/sql/object_address.sql | 6 +- 7 files changed, 238 insertions(+), 2 deletions(-) 14.7% src/backend/catalog/ 75.5% src/test/regress/expected/ 9.7% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..eb9e17fb727 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -752,6 +752,84 @@ SELECT (pg_identify_object(classid, objid, objsubid)).* type | create_property_graph_tests | g2 | create_property_graph_tests.g2 (21 rows) +-- test object address functions with recursive dependency walk +-- covers all property graph object types including indirect dependents +SELECT * +FROM ( + WITH RECURSIVE deps (classid, objid, objsubid, refclassid, refobjid, refobjsubid) AS ( + SELECT classid, objid, objsubid, + refclassid, refobjid, refobjsubid + FROM pg_depend + WHERE refclassid = 'pg_class'::regclass AND + refobjid = 'create_property_graph_tests.gt'::regclass + UNION ALL + SELECT d.classid, d.objid, d.objsubid, + d.refclassid, d.refobjid, d.refobjsubid + FROM pg_depend d + JOIN deps dp ON d.refclassid = dp.classid AND d.refobjid = dp.objid AND d.refobjsubid = dp.objsubid + ) + SELECT pg_describe_object(classid, objid, objsubid) as obj, + pg_identify_object(classid, objid, objsubid) as ident, + pg_identify_object_as_address(classid, objid, objsubid) as addr + FROM deps +) s +ORDER BY obj COLLATE "C", ident::text COLLATE "C"; + obj | ident | addr +----------------------------------------------------------+----------------------------------------------------------------------------+---------------------------------------------------------------------------- + edge e of property graph gt | ("property graph element",,,"e of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,e}",{}) + edge e of property graph gt | ("property graph element",,,"e of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,e}",{}) + edge e of property graph gt | ("property graph element",,,"e of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of property graph gt | ("property graph label",,,"e of create_property_graph_tests.gt") | ("property graph label","{create_property_graph_tests,gt,e}",{}) + label v1 of property graph gt | ("property graph label",,,"v1 of create_property_graph_tests.gt") | ("property graph label","{create_property_graph_tests,gt,v1}",{}) + label v1 of vertex v1 of property graph gt | ("property graph element label",,,"v1 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v1}",{}) + label v1 of vertex v1 of property graph gt | ("property graph element label",,,"v1 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v1}",{}) + label v2 of property graph gt | ("property graph label",,,"v2 of create_property_graph_tests.gt") | ("property graph label","{create_property_graph_tests,gt,v2}",{}) + label v2 of vertex v2 of property graph gt | ("property graph element label",,,"v2 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v2}",{}) + label v2 of vertex v2 of property graph gt | ("property graph element label",,,"v2 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v2}",{}) + property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property a of property graph gt | ("property graph property",,,"a of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,a}",{}) + property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property b of property graph gt | ("property graph property",,,"b of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,b}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of property graph gt | ("property graph property",,,"c of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,c}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of property graph gt | ("property graph property",,,"k1 of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,k1}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of property graph gt | ("property graph property",,,"k2 of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,k2}",{}) + property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property m of property graph gt | ("property graph property",,,"m of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,m}",{}) + property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property n of property graph gt | ("property graph property",,,"n of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,n}",{}) + type gt | (type,create_property_graph_tests,gt,create_property_graph_tests.gt) | (type,{create_property_graph_tests.gt},{}) + type gt[] | (type,create_property_graph_tests,_gt,create_property_graph_tests.gt[]) | (type,{create_property_graph_tests.gt[]},{}) + vertex v1 of property graph gt | ("property graph element",,,"v1 of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,v1}",{}) + vertex v2 of property graph gt | ("property graph element",,,"v2 of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,v2}",{}) +(52 rows) + \a\t SELECT pg_get_propgraphdef('g2'::regclass); CREATE PROPERTY GRAPH create_property_graph_tests.g2 diff --git a/src/test/regress/expected/event_trigger.out b/src/test/regress/expected/event_trigger.out index 065f586310f..ed8d5df397e 100644 --- a/src/test/regress/expected/event_trigger.out +++ b/src/test/regress/expected/event_trigger.out @@ -173,6 +173,23 @@ NOTICE: test_event_trigger: ddl_command_end CREATE USER MAPPING alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; NOTICE: test_event_trigger: ddl_command_end ALTER DEFAULT PRIVILEGES +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE TABLE t2x (i int PRIMARY KEY, j text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); +NOTICE: test_event_trigger: ddl_command_end CREATE PROPERTY GRAPH +DROP PROPERTY GRAPH gx; +NOTICE: test_event_trigger: ddl_command_end DROP PROPERTY GRAPH +DROP TABLE t1x, t2x; +NOTICE: test_event_trigger: ddl_command_end DROP TABLE -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; ERROR: permission denied to change owner of event trigger "regress_event_trigger" diff --git a/src/test/regress/expected/object_address.out b/src/test/regress/expected/object_address.out index 97227d67a54..5e53f0b092e 100644 --- a/src/test/regress/expected/object_address.out +++ b/src/test/regress/expected/object_address.out @@ -67,7 +67,9 @@ DECLARE BEGIN FOR objtype IN VALUES ('toast table'), ('index column'), ('sequence column'), ('toast table column'), ('view column'), ('materialized view column'), - ('property graph element'), ('property graph label'), ('property graph property') + ('property graph element'), ('property graph element label'), + ('property graph label'), ('property graph label property'), + ('property graph property') LOOP BEGIN PERFORM pg_get_object_address(objtype, '{one}', '{}'); @@ -84,7 +86,9 @@ WARNING: error for toast table column: unsupported object type "toast table col WARNING: error for view column: unsupported object type "view column" WARNING: error for materialized view column: unsupported object type "materialized view column" WARNING: error for property graph element: unsupported object type "property graph element" +WARNING: error for property graph element label: unrecognized object type "property graph element label" WARNING: error for property graph label: unsupported object type "property graph label" +WARNING: error for property graph label property: unrecognized object type "property graph label property" WARNING: error for property graph property: unsupported object type "property graph property" -- miscellaneous other errors select * from pg_get_object_address('operator of access method', '{btree,integer_ops,1}', '{int4,bool}'); @@ -593,7 +597,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace @@ -653,6 +659,8 @@ ORDER BY objects.classid, objects.objid, objects.objsubid; ("(""parameter ACL"",,,)")|("(""parameter ACL"",,)")|NULL ("(""property graph element"",,,)")|("(""property graph element"",,)")|NULL ("(""property graph label"",,,)")|("(""property graph label"",,)")|NULL +("(""property graph element label"",,,)")|("(""property graph element label"",,)")|NULL ("(""property graph property"",,,)")|("(""property graph property"",,)")|NULL +("(""property graph label property"",,,)")|("(""property graph label property"",,)")|NULL -- restore normal output mode \a\t diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..9608dd5c4af 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -298,6 +298,29 @@ SELECT (pg_identify_object(classid, objid, objsubid)).* refobjid = 'create_property_graph_tests.g2'::regclass ORDER BY 1, 2, 3, 4; +-- test object address functions with recursive dependency walk +-- covers all property graph object types including indirect dependents +SELECT * +FROM ( + WITH RECURSIVE deps (classid, objid, objsubid, refclassid, refobjid, refobjsubid) AS ( + SELECT classid, objid, objsubid, + refclassid, refobjid, refobjsubid + FROM pg_depend + WHERE refclassid = 'pg_class'::regclass AND + refobjid = 'create_property_graph_tests.gt'::regclass + UNION ALL + SELECT d.classid, d.objid, d.objsubid, + d.refclassid, d.refobjid, d.refobjsubid + FROM pg_depend d + JOIN deps dp ON d.refclassid = dp.classid AND d.refobjid = dp.objid AND d.refobjsubid = dp.objsubid + ) + SELECT pg_describe_object(classid, objid, objsubid) as obj, + pg_identify_object(classid, objid, objsubid) as ident, + pg_identify_object_as_address(classid, objid, objsubid) as addr + FROM deps +) s +ORDER BY obj COLLATE "C", ident::text COLLATE "C"; + \a\t SELECT pg_get_propgraphdef('g2'::regclass); SELECT pg_get_propgraphdef('g3'::regclass); diff --git a/src/test/regress/sql/event_trigger.sql b/src/test/regress/sql/event_trigger.sql index 32e9bb58c5e..271f443378b 100644 --- a/src/test/regress/sql/event_trigger.sql +++ b/src/test/regress/sql/event_trigger.sql @@ -143,6 +143,19 @@ create user mapping for regress_evt_user server useless_server; alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +CREATE TABLE t2x (i int PRIMARY KEY, j text); + +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); + +DROP PROPERTY GRAPH gx; +DROP TABLE t1x, t2x; + -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; diff --git a/src/test/regress/sql/object_address.sql b/src/test/regress/sql/object_address.sql index 1bbe9457c1c..27109d421c7 100644 --- a/src/test/regress/sql/object_address.sql +++ b/src/test/regress/sql/object_address.sql @@ -67,7 +67,9 @@ DECLARE BEGIN FOR objtype IN VALUES ('toast table'), ('index column'), ('sequence column'), ('toast table column'), ('view column'), ('materialized view column'), - ('property graph element'), ('property graph label'), ('property graph property') + ('property graph element'), ('property graph element label'), + ('property graph label'), ('property graph label property'), + ('property graph property') LOOP BEGIN PERFORM pg_get_object_address(objtype, '{one}', '{}'); @@ -282,7 +284,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace -- 2.34.1 --R84XrR4Hgw0dH3Ec-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v2] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-23 09:27 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-23 09:27 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing them to hit the default case and error out with "unsupported object class". During DROP PROPERTY GRAPH, this manifests when an event trigger is active, because pg_event_trigger_ddl_commands() calls these functions. The same code paths are also reachable via pg_identify_object() and pg_identify_object_as_address(). This commit adds the missing cases. Test coverage is added in object_address.sql for these two catalog types via the zero-OID test that exercises pg_identify_object() and pg_identify_object_as_address(). A test in event_trigger.sql verifies that DROP PROPERTY GRAPH works correctly when an event trigger is active. Author: Bertrand Drouvot <[email protected]> Reviewed-by: Michael Paquier <[email protected]> Reviewed-by: Ashutosh Bapat <[email protected]> Discussion: https://postgr.es/m/aej1DkLwhyZWmtxJ@bdtpg --- src/backend/catalog/objectaddress.c | 93 ++++++++++++++++++++ src/test/regress/expected/event_trigger.out | 17 ++++ src/test/regress/expected/object_address.out | 4 + src/test/regress/sql/event_trigger.sql | 13 +++ src/test/regress/sql/object_address.sql | 2 + 5 files changed, 129 insertions(+) 62.4% src/backend/catalog/ 25.6% src/test/regress/expected/ 11.8% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/event_trigger.out b/src/test/regress/expected/event_trigger.out index 065f586310f..ed8d5df397e 100644 --- a/src/test/regress/expected/event_trigger.out +++ b/src/test/regress/expected/event_trigger.out @@ -173,6 +173,23 @@ NOTICE: test_event_trigger: ddl_command_end CREATE USER MAPPING alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; NOTICE: test_event_trigger: ddl_command_end ALTER DEFAULT PRIVILEGES +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE TABLE t2x (i int PRIMARY KEY, j text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); +NOTICE: test_event_trigger: ddl_command_end CREATE PROPERTY GRAPH +DROP PROPERTY GRAPH gx; +NOTICE: test_event_trigger: ddl_command_end DROP PROPERTY GRAPH +DROP TABLE t1x, t2x; +NOTICE: test_event_trigger: ddl_command_end DROP TABLE -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; ERROR: permission denied to change owner of event trigger "regress_event_trigger" diff --git a/src/test/regress/expected/object_address.out b/src/test/regress/expected/object_address.out index 97227d67a54..729c3537f25 100644 --- a/src/test/regress/expected/object_address.out +++ b/src/test/regress/expected/object_address.out @@ -593,7 +593,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace @@ -653,6 +655,8 @@ ORDER BY objects.classid, objects.objid, objects.objsubid; ("(""parameter ACL"",,,)")|("(""parameter ACL"",,)")|NULL ("(""property graph element"",,,)")|("(""property graph element"",,)")|NULL ("(""property graph label"",,,)")|("(""property graph label"",,)")|NULL +("(""property graph element label"",,,)")|("(""property graph element label"",,)")|NULL ("(""property graph property"",,,)")|("(""property graph property"",,)")|NULL +("(""property graph label property"",,,)")|("(""property graph label property"",,)")|NULL -- restore normal output mode \a\t diff --git a/src/test/regress/sql/event_trigger.sql b/src/test/regress/sql/event_trigger.sql index 32e9bb58c5e..271f443378b 100644 --- a/src/test/regress/sql/event_trigger.sql +++ b/src/test/regress/sql/event_trigger.sql @@ -143,6 +143,19 @@ create user mapping for regress_evt_user server useless_server; alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +CREATE TABLE t2x (i int PRIMARY KEY, j text); + +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); + +DROP PROPERTY GRAPH gx; +DROP TABLE t1x, t2x; + -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; diff --git a/src/test/regress/sql/object_address.sql b/src/test/regress/sql/object_address.sql index 1bbe9457c1c..620dacf1045 100644 --- a/src/test/regress/sql/object_address.sql +++ b/src/test/regress/sql/object_address.sql @@ -282,7 +282,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace -- 2.34.1 --gtUR827Uq8d5gVsQ-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v3] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-23 09:27 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-23 09:27 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing them to hit the default case and error out with "unsupported object class". During DROP PROPERTY GRAPH, this manifests when an event trigger is active, because pg_event_trigger_ddl_commands() calls these functions. The same code paths are also reachable via pg_identify_object() and pg_identify_object_as_address(). This commit adds the missing cases. Test coverage is added in object_address.sql for these two catalog types and in create_property_graph.sql covering all property graph object types. A test in event_trigger.sql verifies that DROP PROPERTY GRAPH works correctly when an event trigger is active. Author: Bertrand Drouvot <[email protected]> Reviewed-by: Michael Paquier <[email protected]> Reviewed-by: Ashutosh Bapat <[email protected]> Discussion: https://postgr.es/m/aej1DkLwhyZWmtxJ@bdtpg --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 78 ++++++++++++++++ src/test/regress/expected/event_trigger.out | 17 ++++ src/test/regress/expected/object_address.out | 10 +- .../regress/sql/create_property_graph.sql | 23 +++++ src/test/regress/sql/event_trigger.sql | 13 +++ src/test/regress/sql/object_address.sql | 6 +- 7 files changed, 238 insertions(+), 2 deletions(-) 14.7% src/backend/catalog/ 75.5% src/test/regress/expected/ 9.7% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..eb9e17fb727 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -752,6 +752,84 @@ SELECT (pg_identify_object(classid, objid, objsubid)).* type | create_property_graph_tests | g2 | create_property_graph_tests.g2 (21 rows) +-- test object address functions with recursive dependency walk +-- covers all property graph object types including indirect dependents +SELECT * +FROM ( + WITH RECURSIVE deps (classid, objid, objsubid, refclassid, refobjid, refobjsubid) AS ( + SELECT classid, objid, objsubid, + refclassid, refobjid, refobjsubid + FROM pg_depend + WHERE refclassid = 'pg_class'::regclass AND + refobjid = 'create_property_graph_tests.gt'::regclass + UNION ALL + SELECT d.classid, d.objid, d.objsubid, + d.refclassid, d.refobjid, d.refobjsubid + FROM pg_depend d + JOIN deps dp ON d.refclassid = dp.classid AND d.refobjid = dp.objid AND d.refobjsubid = dp.objsubid + ) + SELECT pg_describe_object(classid, objid, objsubid) as obj, + pg_identify_object(classid, objid, objsubid) as ident, + pg_identify_object_as_address(classid, objid, objsubid) as addr + FROM deps +) s +ORDER BY obj COLLATE "C", ident::text COLLATE "C"; + obj | ident | addr +----------------------------------------------------------+----------------------------------------------------------------------------+---------------------------------------------------------------------------- + edge e of property graph gt | ("property graph element",,,"e of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,e}",{}) + edge e of property graph gt | ("property graph element",,,"e of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,e}",{}) + edge e of property graph gt | ("property graph element",,,"e of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of property graph gt | ("property graph label",,,"e of create_property_graph_tests.gt") | ("property graph label","{create_property_graph_tests,gt,e}",{}) + label v1 of property graph gt | ("property graph label",,,"v1 of create_property_graph_tests.gt") | ("property graph label","{create_property_graph_tests,gt,v1}",{}) + label v1 of vertex v1 of property graph gt | ("property graph element label",,,"v1 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v1}",{}) + label v1 of vertex v1 of property graph gt | ("property graph element label",,,"v1 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v1}",{}) + label v2 of property graph gt | ("property graph label",,,"v2 of create_property_graph_tests.gt") | ("property graph label","{create_property_graph_tests,gt,v2}",{}) + label v2 of vertex v2 of property graph gt | ("property graph element label",,,"v2 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v2}",{}) + label v2 of vertex v2 of property graph gt | ("property graph element label",,,"v2 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v2}",{}) + property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property a of property graph gt | ("property graph property",,,"a of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,a}",{}) + property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property b of property graph gt | ("property graph property",,,"b of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,b}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of property graph gt | ("property graph property",,,"c of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,c}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of property graph gt | ("property graph property",,,"k1 of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,k1}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of property graph gt | ("property graph property",,,"k2 of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,k2}",{}) + property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property m of property graph gt | ("property graph property",,,"m of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,m}",{}) + property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property n of property graph gt | ("property graph property",,,"n of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,n}",{}) + type gt | (type,create_property_graph_tests,gt,create_property_graph_tests.gt) | (type,{create_property_graph_tests.gt},{}) + type gt[] | (type,create_property_graph_tests,_gt,create_property_graph_tests.gt[]) | (type,{create_property_graph_tests.gt[]},{}) + vertex v1 of property graph gt | ("property graph element",,,"v1 of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,v1}",{}) + vertex v2 of property graph gt | ("property graph element",,,"v2 of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,v2}",{}) +(52 rows) + \a\t SELECT pg_get_propgraphdef('g2'::regclass); CREATE PROPERTY GRAPH create_property_graph_tests.g2 diff --git a/src/test/regress/expected/event_trigger.out b/src/test/regress/expected/event_trigger.out index 065f586310f..ed8d5df397e 100644 --- a/src/test/regress/expected/event_trigger.out +++ b/src/test/regress/expected/event_trigger.out @@ -173,6 +173,23 @@ NOTICE: test_event_trigger: ddl_command_end CREATE USER MAPPING alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; NOTICE: test_event_trigger: ddl_command_end ALTER DEFAULT PRIVILEGES +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE TABLE t2x (i int PRIMARY KEY, j text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); +NOTICE: test_event_trigger: ddl_command_end CREATE PROPERTY GRAPH +DROP PROPERTY GRAPH gx; +NOTICE: test_event_trigger: ddl_command_end DROP PROPERTY GRAPH +DROP TABLE t1x, t2x; +NOTICE: test_event_trigger: ddl_command_end DROP TABLE -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; ERROR: permission denied to change owner of event trigger "regress_event_trigger" diff --git a/src/test/regress/expected/object_address.out b/src/test/regress/expected/object_address.out index 97227d67a54..5e53f0b092e 100644 --- a/src/test/regress/expected/object_address.out +++ b/src/test/regress/expected/object_address.out @@ -67,7 +67,9 @@ DECLARE BEGIN FOR objtype IN VALUES ('toast table'), ('index column'), ('sequence column'), ('toast table column'), ('view column'), ('materialized view column'), - ('property graph element'), ('property graph label'), ('property graph property') + ('property graph element'), ('property graph element label'), + ('property graph label'), ('property graph label property'), + ('property graph property') LOOP BEGIN PERFORM pg_get_object_address(objtype, '{one}', '{}'); @@ -84,7 +86,9 @@ WARNING: error for toast table column: unsupported object type "toast table col WARNING: error for view column: unsupported object type "view column" WARNING: error for materialized view column: unsupported object type "materialized view column" WARNING: error for property graph element: unsupported object type "property graph element" +WARNING: error for property graph element label: unrecognized object type "property graph element label" WARNING: error for property graph label: unsupported object type "property graph label" +WARNING: error for property graph label property: unrecognized object type "property graph label property" WARNING: error for property graph property: unsupported object type "property graph property" -- miscellaneous other errors select * from pg_get_object_address('operator of access method', '{btree,integer_ops,1}', '{int4,bool}'); @@ -593,7 +597,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace @@ -653,6 +659,8 @@ ORDER BY objects.classid, objects.objid, objects.objsubid; ("(""parameter ACL"",,,)")|("(""parameter ACL"",,)")|NULL ("(""property graph element"",,,)")|("(""property graph element"",,)")|NULL ("(""property graph label"",,,)")|("(""property graph label"",,)")|NULL +("(""property graph element label"",,,)")|("(""property graph element label"",,)")|NULL ("(""property graph property"",,,)")|("(""property graph property"",,)")|NULL +("(""property graph label property"",,,)")|("(""property graph label property"",,)")|NULL -- restore normal output mode \a\t diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..9608dd5c4af 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -298,6 +298,29 @@ SELECT (pg_identify_object(classid, objid, objsubid)).* refobjid = 'create_property_graph_tests.g2'::regclass ORDER BY 1, 2, 3, 4; +-- test object address functions with recursive dependency walk +-- covers all property graph object types including indirect dependents +SELECT * +FROM ( + WITH RECURSIVE deps (classid, objid, objsubid, refclassid, refobjid, refobjsubid) AS ( + SELECT classid, objid, objsubid, + refclassid, refobjid, refobjsubid + FROM pg_depend + WHERE refclassid = 'pg_class'::regclass AND + refobjid = 'create_property_graph_tests.gt'::regclass + UNION ALL + SELECT d.classid, d.objid, d.objsubid, + d.refclassid, d.refobjid, d.refobjsubid + FROM pg_depend d + JOIN deps dp ON d.refclassid = dp.classid AND d.refobjid = dp.objid AND d.refobjsubid = dp.objsubid + ) + SELECT pg_describe_object(classid, objid, objsubid) as obj, + pg_identify_object(classid, objid, objsubid) as ident, + pg_identify_object_as_address(classid, objid, objsubid) as addr + FROM deps +) s +ORDER BY obj COLLATE "C", ident::text COLLATE "C"; + \a\t SELECT pg_get_propgraphdef('g2'::regclass); SELECT pg_get_propgraphdef('g3'::regclass); diff --git a/src/test/regress/sql/event_trigger.sql b/src/test/regress/sql/event_trigger.sql index 32e9bb58c5e..271f443378b 100644 --- a/src/test/regress/sql/event_trigger.sql +++ b/src/test/regress/sql/event_trigger.sql @@ -143,6 +143,19 @@ create user mapping for regress_evt_user server useless_server; alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +CREATE TABLE t2x (i int PRIMARY KEY, j text); + +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); + +DROP PROPERTY GRAPH gx; +DROP TABLE t1x, t2x; + -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; diff --git a/src/test/regress/sql/object_address.sql b/src/test/regress/sql/object_address.sql index 1bbe9457c1c..27109d421c7 100644 --- a/src/test/regress/sql/object_address.sql +++ b/src/test/regress/sql/object_address.sql @@ -67,7 +67,9 @@ DECLARE BEGIN FOR objtype IN VALUES ('toast table'), ('index column'), ('sequence column'), ('toast table column'), ('view column'), ('materialized view column'), - ('property graph element'), ('property graph label'), ('property graph property') + ('property graph element'), ('property graph element label'), + ('property graph label'), ('property graph label property'), + ('property graph property') LOOP BEGIN PERFORM pg_get_object_address(objtype, '{one}', '{}'); @@ -282,7 +284,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace -- 2.34.1 --R84XrR4Hgw0dH3Ec-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v2] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-23 09:27 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-23 09:27 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing them to hit the default case and error out with "unsupported object class". During DROP PROPERTY GRAPH, this manifests when an event trigger is active, because pg_event_trigger_ddl_commands() calls these functions. The same code paths are also reachable via pg_identify_object() and pg_identify_object_as_address(). This commit adds the missing cases. Test coverage is added in object_address.sql for these two catalog types via the zero-OID test that exercises pg_identify_object() and pg_identify_object_as_address(). A test in event_trigger.sql verifies that DROP PROPERTY GRAPH works correctly when an event trigger is active. Author: Bertrand Drouvot <[email protected]> Reviewed-by: Michael Paquier <[email protected]> Reviewed-by: Ashutosh Bapat <[email protected]> Discussion: https://postgr.es/m/aej1DkLwhyZWmtxJ@bdtpg --- src/backend/catalog/objectaddress.c | 93 ++++++++++++++++++++ src/test/regress/expected/event_trigger.out | 17 ++++ src/test/regress/expected/object_address.out | 4 + src/test/regress/sql/event_trigger.sql | 13 +++ src/test/regress/sql/object_address.sql | 2 + 5 files changed, 129 insertions(+) 62.4% src/backend/catalog/ 25.6% src/test/regress/expected/ 11.8% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/event_trigger.out b/src/test/regress/expected/event_trigger.out index 065f586310f..ed8d5df397e 100644 --- a/src/test/regress/expected/event_trigger.out +++ b/src/test/regress/expected/event_trigger.out @@ -173,6 +173,23 @@ NOTICE: test_event_trigger: ddl_command_end CREATE USER MAPPING alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; NOTICE: test_event_trigger: ddl_command_end ALTER DEFAULT PRIVILEGES +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE TABLE t2x (i int PRIMARY KEY, j text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); +NOTICE: test_event_trigger: ddl_command_end CREATE PROPERTY GRAPH +DROP PROPERTY GRAPH gx; +NOTICE: test_event_trigger: ddl_command_end DROP PROPERTY GRAPH +DROP TABLE t1x, t2x; +NOTICE: test_event_trigger: ddl_command_end DROP TABLE -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; ERROR: permission denied to change owner of event trigger "regress_event_trigger" diff --git a/src/test/regress/expected/object_address.out b/src/test/regress/expected/object_address.out index 97227d67a54..729c3537f25 100644 --- a/src/test/regress/expected/object_address.out +++ b/src/test/regress/expected/object_address.out @@ -593,7 +593,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace @@ -653,6 +655,8 @@ ORDER BY objects.classid, objects.objid, objects.objsubid; ("(""parameter ACL"",,,)")|("(""parameter ACL"",,)")|NULL ("(""property graph element"",,,)")|("(""property graph element"",,)")|NULL ("(""property graph label"",,,)")|("(""property graph label"",,)")|NULL +("(""property graph element label"",,,)")|("(""property graph element label"",,)")|NULL ("(""property graph property"",,,)")|("(""property graph property"",,)")|NULL +("(""property graph label property"",,,)")|("(""property graph label property"",,)")|NULL -- restore normal output mode \a\t diff --git a/src/test/regress/sql/event_trigger.sql b/src/test/regress/sql/event_trigger.sql index 32e9bb58c5e..271f443378b 100644 --- a/src/test/regress/sql/event_trigger.sql +++ b/src/test/regress/sql/event_trigger.sql @@ -143,6 +143,19 @@ create user mapping for regress_evt_user server useless_server; alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +CREATE TABLE t2x (i int PRIMARY KEY, j text); + +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); + +DROP PROPERTY GRAPH gx; +DROP TABLE t1x, t2x; + -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; diff --git a/src/test/regress/sql/object_address.sql b/src/test/regress/sql/object_address.sql index 1bbe9457c1c..620dacf1045 100644 --- a/src/test/regress/sql/object_address.sql +++ b/src/test/regress/sql/object_address.sql @@ -282,7 +282,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace -- 2.34.1 --gtUR827Uq8d5gVsQ-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v3] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-23 09:27 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-23 09:27 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing them to hit the default case and error out with "unsupported object class". During DROP PROPERTY GRAPH, this manifests when an event trigger is active, because pg_event_trigger_ddl_commands() calls these functions. The same code paths are also reachable via pg_identify_object() and pg_identify_object_as_address(). This commit adds the missing cases. Test coverage is added in object_address.sql for these two catalog types and in create_property_graph.sql covering all property graph object types. A test in event_trigger.sql verifies that DROP PROPERTY GRAPH works correctly when an event trigger is active. Author: Bertrand Drouvot <[email protected]> Reviewed-by: Michael Paquier <[email protected]> Reviewed-by: Ashutosh Bapat <[email protected]> Discussion: https://postgr.es/m/aej1DkLwhyZWmtxJ@bdtpg --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 78 ++++++++++++++++ src/test/regress/expected/event_trigger.out | 17 ++++ src/test/regress/expected/object_address.out | 10 +- .../regress/sql/create_property_graph.sql | 23 +++++ src/test/regress/sql/event_trigger.sql | 13 +++ src/test/regress/sql/object_address.sql | 6 +- 7 files changed, 238 insertions(+), 2 deletions(-) 14.7% src/backend/catalog/ 75.5% src/test/regress/expected/ 9.7% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..eb9e17fb727 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -752,6 +752,84 @@ SELECT (pg_identify_object(classid, objid, objsubid)).* type | create_property_graph_tests | g2 | create_property_graph_tests.g2 (21 rows) +-- test object address functions with recursive dependency walk +-- covers all property graph object types including indirect dependents +SELECT * +FROM ( + WITH RECURSIVE deps (classid, objid, objsubid, refclassid, refobjid, refobjsubid) AS ( + SELECT classid, objid, objsubid, + refclassid, refobjid, refobjsubid + FROM pg_depend + WHERE refclassid = 'pg_class'::regclass AND + refobjid = 'create_property_graph_tests.gt'::regclass + UNION ALL + SELECT d.classid, d.objid, d.objsubid, + d.refclassid, d.refobjid, d.refobjsubid + FROM pg_depend d + JOIN deps dp ON d.refclassid = dp.classid AND d.refobjid = dp.objid AND d.refobjsubid = dp.objsubid + ) + SELECT pg_describe_object(classid, objid, objsubid) as obj, + pg_identify_object(classid, objid, objsubid) as ident, + pg_identify_object_as_address(classid, objid, objsubid) as addr + FROM deps +) s +ORDER BY obj COLLATE "C", ident::text COLLATE "C"; + obj | ident | addr +----------------------------------------------------------+----------------------------------------------------------------------------+---------------------------------------------------------------------------- + edge e of property graph gt | ("property graph element",,,"e of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,e}",{}) + edge e of property graph gt | ("property graph element",,,"e of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,e}",{}) + edge e of property graph gt | ("property graph element",,,"e of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of property graph gt | ("property graph label",,,"e of create_property_graph_tests.gt") | ("property graph label","{create_property_graph_tests,gt,e}",{}) + label v1 of property graph gt | ("property graph label",,,"v1 of create_property_graph_tests.gt") | ("property graph label","{create_property_graph_tests,gt,v1}",{}) + label v1 of vertex v1 of property graph gt | ("property graph element label",,,"v1 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v1}",{}) + label v1 of vertex v1 of property graph gt | ("property graph element label",,,"v1 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v1}",{}) + label v2 of property graph gt | ("property graph label",,,"v2 of create_property_graph_tests.gt") | ("property graph label","{create_property_graph_tests,gt,v2}",{}) + label v2 of vertex v2 of property graph gt | ("property graph element label",,,"v2 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v2}",{}) + label v2 of vertex v2 of property graph gt | ("property graph element label",,,"v2 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v2}",{}) + property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property a of property graph gt | ("property graph property",,,"a of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,a}",{}) + property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property b of property graph gt | ("property graph property",,,"b of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,b}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of property graph gt | ("property graph property",,,"c of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,c}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of property graph gt | ("property graph property",,,"k1 of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,k1}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of property graph gt | ("property graph property",,,"k2 of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,k2}",{}) + property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property m of property graph gt | ("property graph property",,,"m of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,m}",{}) + property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property n of property graph gt | ("property graph property",,,"n of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,n}",{}) + type gt | (type,create_property_graph_tests,gt,create_property_graph_tests.gt) | (type,{create_property_graph_tests.gt},{}) + type gt[] | (type,create_property_graph_tests,_gt,create_property_graph_tests.gt[]) | (type,{create_property_graph_tests.gt[]},{}) + vertex v1 of property graph gt | ("property graph element",,,"v1 of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,v1}",{}) + vertex v2 of property graph gt | ("property graph element",,,"v2 of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,v2}",{}) +(52 rows) + \a\t SELECT pg_get_propgraphdef('g2'::regclass); CREATE PROPERTY GRAPH create_property_graph_tests.g2 diff --git a/src/test/regress/expected/event_trigger.out b/src/test/regress/expected/event_trigger.out index 065f586310f..ed8d5df397e 100644 --- a/src/test/regress/expected/event_trigger.out +++ b/src/test/regress/expected/event_trigger.out @@ -173,6 +173,23 @@ NOTICE: test_event_trigger: ddl_command_end CREATE USER MAPPING alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; NOTICE: test_event_trigger: ddl_command_end ALTER DEFAULT PRIVILEGES +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE TABLE t2x (i int PRIMARY KEY, j text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); +NOTICE: test_event_trigger: ddl_command_end CREATE PROPERTY GRAPH +DROP PROPERTY GRAPH gx; +NOTICE: test_event_trigger: ddl_command_end DROP PROPERTY GRAPH +DROP TABLE t1x, t2x; +NOTICE: test_event_trigger: ddl_command_end DROP TABLE -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; ERROR: permission denied to change owner of event trigger "regress_event_trigger" diff --git a/src/test/regress/expected/object_address.out b/src/test/regress/expected/object_address.out index 97227d67a54..5e53f0b092e 100644 --- a/src/test/regress/expected/object_address.out +++ b/src/test/regress/expected/object_address.out @@ -67,7 +67,9 @@ DECLARE BEGIN FOR objtype IN VALUES ('toast table'), ('index column'), ('sequence column'), ('toast table column'), ('view column'), ('materialized view column'), - ('property graph element'), ('property graph label'), ('property graph property') + ('property graph element'), ('property graph element label'), + ('property graph label'), ('property graph label property'), + ('property graph property') LOOP BEGIN PERFORM pg_get_object_address(objtype, '{one}', '{}'); @@ -84,7 +86,9 @@ WARNING: error for toast table column: unsupported object type "toast table col WARNING: error for view column: unsupported object type "view column" WARNING: error for materialized view column: unsupported object type "materialized view column" WARNING: error for property graph element: unsupported object type "property graph element" +WARNING: error for property graph element label: unrecognized object type "property graph element label" WARNING: error for property graph label: unsupported object type "property graph label" +WARNING: error for property graph label property: unrecognized object type "property graph label property" WARNING: error for property graph property: unsupported object type "property graph property" -- miscellaneous other errors select * from pg_get_object_address('operator of access method', '{btree,integer_ops,1}', '{int4,bool}'); @@ -593,7 +597,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace @@ -653,6 +659,8 @@ ORDER BY objects.classid, objects.objid, objects.objsubid; ("(""parameter ACL"",,,)")|("(""parameter ACL"",,)")|NULL ("(""property graph element"",,,)")|("(""property graph element"",,)")|NULL ("(""property graph label"",,,)")|("(""property graph label"",,)")|NULL +("(""property graph element label"",,,)")|("(""property graph element label"",,)")|NULL ("(""property graph property"",,,)")|("(""property graph property"",,)")|NULL +("(""property graph label property"",,,)")|("(""property graph label property"",,)")|NULL -- restore normal output mode \a\t diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..9608dd5c4af 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -298,6 +298,29 @@ SELECT (pg_identify_object(classid, objid, objsubid)).* refobjid = 'create_property_graph_tests.g2'::regclass ORDER BY 1, 2, 3, 4; +-- test object address functions with recursive dependency walk +-- covers all property graph object types including indirect dependents +SELECT * +FROM ( + WITH RECURSIVE deps (classid, objid, objsubid, refclassid, refobjid, refobjsubid) AS ( + SELECT classid, objid, objsubid, + refclassid, refobjid, refobjsubid + FROM pg_depend + WHERE refclassid = 'pg_class'::regclass AND + refobjid = 'create_property_graph_tests.gt'::regclass + UNION ALL + SELECT d.classid, d.objid, d.objsubid, + d.refclassid, d.refobjid, d.refobjsubid + FROM pg_depend d + JOIN deps dp ON d.refclassid = dp.classid AND d.refobjid = dp.objid AND d.refobjsubid = dp.objsubid + ) + SELECT pg_describe_object(classid, objid, objsubid) as obj, + pg_identify_object(classid, objid, objsubid) as ident, + pg_identify_object_as_address(classid, objid, objsubid) as addr + FROM deps +) s +ORDER BY obj COLLATE "C", ident::text COLLATE "C"; + \a\t SELECT pg_get_propgraphdef('g2'::regclass); SELECT pg_get_propgraphdef('g3'::regclass); diff --git a/src/test/regress/sql/event_trigger.sql b/src/test/regress/sql/event_trigger.sql index 32e9bb58c5e..271f443378b 100644 --- a/src/test/regress/sql/event_trigger.sql +++ b/src/test/regress/sql/event_trigger.sql @@ -143,6 +143,19 @@ create user mapping for regress_evt_user server useless_server; alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +CREATE TABLE t2x (i int PRIMARY KEY, j text); + +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); + +DROP PROPERTY GRAPH gx; +DROP TABLE t1x, t2x; + -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; diff --git a/src/test/regress/sql/object_address.sql b/src/test/regress/sql/object_address.sql index 1bbe9457c1c..27109d421c7 100644 --- a/src/test/regress/sql/object_address.sql +++ b/src/test/regress/sql/object_address.sql @@ -67,7 +67,9 @@ DECLARE BEGIN FOR objtype IN VALUES ('toast table'), ('index column'), ('sequence column'), ('toast table column'), ('view column'), ('materialized view column'), - ('property graph element'), ('property graph label'), ('property graph property') + ('property graph element'), ('property graph element label'), + ('property graph label'), ('property graph label property'), + ('property graph property') LOOP BEGIN PERFORM pg_get_object_address(objtype, '{one}', '{}'); @@ -282,7 +284,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace -- 2.34.1 --R84XrR4Hgw0dH3Ec-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v3] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-23 09:27 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-23 09:27 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing them to hit the default case and error out with "unsupported object class". During DROP PROPERTY GRAPH, this manifests when an event trigger is active, because pg_event_trigger_ddl_commands() calls these functions. The same code paths are also reachable via pg_identify_object() and pg_identify_object_as_address(). This commit adds the missing cases. Test coverage is added in object_address.sql for these two catalog types and in create_property_graph.sql covering all property graph object types. A test in event_trigger.sql verifies that DROP PROPERTY GRAPH works correctly when an event trigger is active. Author: Bertrand Drouvot <[email protected]> Reviewed-by: Michael Paquier <[email protected]> Reviewed-by: Ashutosh Bapat <[email protected]> Discussion: https://postgr.es/m/aej1DkLwhyZWmtxJ@bdtpg --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 78 ++++++++++++++++ src/test/regress/expected/event_trigger.out | 17 ++++ src/test/regress/expected/object_address.out | 10 +- .../regress/sql/create_property_graph.sql | 23 +++++ src/test/regress/sql/event_trigger.sql | 13 +++ src/test/regress/sql/object_address.sql | 6 +- 7 files changed, 238 insertions(+), 2 deletions(-) 14.7% src/backend/catalog/ 75.5% src/test/regress/expected/ 9.7% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..eb9e17fb727 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -752,6 +752,84 @@ SELECT (pg_identify_object(classid, objid, objsubid)).* type | create_property_graph_tests | g2 | create_property_graph_tests.g2 (21 rows) +-- test object address functions with recursive dependency walk +-- covers all property graph object types including indirect dependents +SELECT * +FROM ( + WITH RECURSIVE deps (classid, objid, objsubid, refclassid, refobjid, refobjsubid) AS ( + SELECT classid, objid, objsubid, + refclassid, refobjid, refobjsubid + FROM pg_depend + WHERE refclassid = 'pg_class'::regclass AND + refobjid = 'create_property_graph_tests.gt'::regclass + UNION ALL + SELECT d.classid, d.objid, d.objsubid, + d.refclassid, d.refobjid, d.refobjsubid + FROM pg_depend d + JOIN deps dp ON d.refclassid = dp.classid AND d.refobjid = dp.objid AND d.refobjsubid = dp.objsubid + ) + SELECT pg_describe_object(classid, objid, objsubid) as obj, + pg_identify_object(classid, objid, objsubid) as ident, + pg_identify_object_as_address(classid, objid, objsubid) as addr + FROM deps +) s +ORDER BY obj COLLATE "C", ident::text COLLATE "C"; + obj | ident | addr +----------------------------------------------------------+----------------------------------------------------------------------------+---------------------------------------------------------------------------- + edge e of property graph gt | ("property graph element",,,"e of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,e}",{}) + edge e of property graph gt | ("property graph element",,,"e of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,e}",{}) + edge e of property graph gt | ("property graph element",,,"e of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of property graph gt | ("property graph label",,,"e of create_property_graph_tests.gt") | ("property graph label","{create_property_graph_tests,gt,e}",{}) + label v1 of property graph gt | ("property graph label",,,"v1 of create_property_graph_tests.gt") | ("property graph label","{create_property_graph_tests,gt,v1}",{}) + label v1 of vertex v1 of property graph gt | ("property graph element label",,,"v1 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v1}",{}) + label v1 of vertex v1 of property graph gt | ("property graph element label",,,"v1 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v1}",{}) + label v2 of property graph gt | ("property graph label",,,"v2 of create_property_graph_tests.gt") | ("property graph label","{create_property_graph_tests,gt,v2}",{}) + label v2 of vertex v2 of property graph gt | ("property graph element label",,,"v2 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v2}",{}) + label v2 of vertex v2 of property graph gt | ("property graph element label",,,"v2 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v2}",{}) + property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property a of property graph gt | ("property graph property",,,"a of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,a}",{}) + property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property b of property graph gt | ("property graph property",,,"b of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,b}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of property graph gt | ("property graph property",,,"c of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,c}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of property graph gt | ("property graph property",,,"k1 of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,k1}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of property graph gt | ("property graph property",,,"k2 of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,k2}",{}) + property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property m of property graph gt | ("property graph property",,,"m of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,m}",{}) + property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property n of property graph gt | ("property graph property",,,"n of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,n}",{}) + type gt | (type,create_property_graph_tests,gt,create_property_graph_tests.gt) | (type,{create_property_graph_tests.gt},{}) + type gt[] | (type,create_property_graph_tests,_gt,create_property_graph_tests.gt[]) | (type,{create_property_graph_tests.gt[]},{}) + vertex v1 of property graph gt | ("property graph element",,,"v1 of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,v1}",{}) + vertex v2 of property graph gt | ("property graph element",,,"v2 of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,v2}",{}) +(52 rows) + \a\t SELECT pg_get_propgraphdef('g2'::regclass); CREATE PROPERTY GRAPH create_property_graph_tests.g2 diff --git a/src/test/regress/expected/event_trigger.out b/src/test/regress/expected/event_trigger.out index 065f586310f..ed8d5df397e 100644 --- a/src/test/regress/expected/event_trigger.out +++ b/src/test/regress/expected/event_trigger.out @@ -173,6 +173,23 @@ NOTICE: test_event_trigger: ddl_command_end CREATE USER MAPPING alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; NOTICE: test_event_trigger: ddl_command_end ALTER DEFAULT PRIVILEGES +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE TABLE t2x (i int PRIMARY KEY, j text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); +NOTICE: test_event_trigger: ddl_command_end CREATE PROPERTY GRAPH +DROP PROPERTY GRAPH gx; +NOTICE: test_event_trigger: ddl_command_end DROP PROPERTY GRAPH +DROP TABLE t1x, t2x; +NOTICE: test_event_trigger: ddl_command_end DROP TABLE -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; ERROR: permission denied to change owner of event trigger "regress_event_trigger" diff --git a/src/test/regress/expected/object_address.out b/src/test/regress/expected/object_address.out index 97227d67a54..5e53f0b092e 100644 --- a/src/test/regress/expected/object_address.out +++ b/src/test/regress/expected/object_address.out @@ -67,7 +67,9 @@ DECLARE BEGIN FOR objtype IN VALUES ('toast table'), ('index column'), ('sequence column'), ('toast table column'), ('view column'), ('materialized view column'), - ('property graph element'), ('property graph label'), ('property graph property') + ('property graph element'), ('property graph element label'), + ('property graph label'), ('property graph label property'), + ('property graph property') LOOP BEGIN PERFORM pg_get_object_address(objtype, '{one}', '{}'); @@ -84,7 +86,9 @@ WARNING: error for toast table column: unsupported object type "toast table col WARNING: error for view column: unsupported object type "view column" WARNING: error for materialized view column: unsupported object type "materialized view column" WARNING: error for property graph element: unsupported object type "property graph element" +WARNING: error for property graph element label: unrecognized object type "property graph element label" WARNING: error for property graph label: unsupported object type "property graph label" +WARNING: error for property graph label property: unrecognized object type "property graph label property" WARNING: error for property graph property: unsupported object type "property graph property" -- miscellaneous other errors select * from pg_get_object_address('operator of access method', '{btree,integer_ops,1}', '{int4,bool}'); @@ -593,7 +597,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace @@ -653,6 +659,8 @@ ORDER BY objects.classid, objects.objid, objects.objsubid; ("(""parameter ACL"",,,)")|("(""parameter ACL"",,)")|NULL ("(""property graph element"",,,)")|("(""property graph element"",,)")|NULL ("(""property graph label"",,,)")|("(""property graph label"",,)")|NULL +("(""property graph element label"",,,)")|("(""property graph element label"",,)")|NULL ("(""property graph property"",,,)")|("(""property graph property"",,)")|NULL +("(""property graph label property"",,,)")|("(""property graph label property"",,)")|NULL -- restore normal output mode \a\t diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..9608dd5c4af 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -298,6 +298,29 @@ SELECT (pg_identify_object(classid, objid, objsubid)).* refobjid = 'create_property_graph_tests.g2'::regclass ORDER BY 1, 2, 3, 4; +-- test object address functions with recursive dependency walk +-- covers all property graph object types including indirect dependents +SELECT * +FROM ( + WITH RECURSIVE deps (classid, objid, objsubid, refclassid, refobjid, refobjsubid) AS ( + SELECT classid, objid, objsubid, + refclassid, refobjid, refobjsubid + FROM pg_depend + WHERE refclassid = 'pg_class'::regclass AND + refobjid = 'create_property_graph_tests.gt'::regclass + UNION ALL + SELECT d.classid, d.objid, d.objsubid, + d.refclassid, d.refobjid, d.refobjsubid + FROM pg_depend d + JOIN deps dp ON d.refclassid = dp.classid AND d.refobjid = dp.objid AND d.refobjsubid = dp.objsubid + ) + SELECT pg_describe_object(classid, objid, objsubid) as obj, + pg_identify_object(classid, objid, objsubid) as ident, + pg_identify_object_as_address(classid, objid, objsubid) as addr + FROM deps +) s +ORDER BY obj COLLATE "C", ident::text COLLATE "C"; + \a\t SELECT pg_get_propgraphdef('g2'::regclass); SELECT pg_get_propgraphdef('g3'::regclass); diff --git a/src/test/regress/sql/event_trigger.sql b/src/test/regress/sql/event_trigger.sql index 32e9bb58c5e..271f443378b 100644 --- a/src/test/regress/sql/event_trigger.sql +++ b/src/test/regress/sql/event_trigger.sql @@ -143,6 +143,19 @@ create user mapping for regress_evt_user server useless_server; alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +CREATE TABLE t2x (i int PRIMARY KEY, j text); + +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); + +DROP PROPERTY GRAPH gx; +DROP TABLE t1x, t2x; + -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; diff --git a/src/test/regress/sql/object_address.sql b/src/test/regress/sql/object_address.sql index 1bbe9457c1c..27109d421c7 100644 --- a/src/test/regress/sql/object_address.sql +++ b/src/test/regress/sql/object_address.sql @@ -67,7 +67,9 @@ DECLARE BEGIN FOR objtype IN VALUES ('toast table'), ('index column'), ('sequence column'), ('toast table column'), ('view column'), ('materialized view column'), - ('property graph element'), ('property graph label'), ('property graph property') + ('property graph element'), ('property graph element label'), + ('property graph label'), ('property graph label property'), + ('property graph property') LOOP BEGIN PERFORM pg_get_object_address(objtype, '{one}', '{}'); @@ -282,7 +284,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace -- 2.34.1 --R84XrR4Hgw0dH3Ec-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v2] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-23 09:27 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-23 09:27 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing them to hit the default case and error out with "unsupported object class". During DROP PROPERTY GRAPH, this manifests when an event trigger is active, because pg_event_trigger_ddl_commands() calls these functions. The same code paths are also reachable via pg_identify_object() and pg_identify_object_as_address(). This commit adds the missing cases. Test coverage is added in object_address.sql for these two catalog types via the zero-OID test that exercises pg_identify_object() and pg_identify_object_as_address(). A test in event_trigger.sql verifies that DROP PROPERTY GRAPH works correctly when an event trigger is active. Author: Bertrand Drouvot <[email protected]> Reviewed-by: Michael Paquier <[email protected]> Reviewed-by: Ashutosh Bapat <[email protected]> Discussion: https://postgr.es/m/aej1DkLwhyZWmtxJ@bdtpg --- src/backend/catalog/objectaddress.c | 93 ++++++++++++++++++++ src/test/regress/expected/event_trigger.out | 17 ++++ src/test/regress/expected/object_address.out | 4 + src/test/regress/sql/event_trigger.sql | 13 +++ src/test/regress/sql/object_address.sql | 2 + 5 files changed, 129 insertions(+) 62.4% src/backend/catalog/ 25.6% src/test/regress/expected/ 11.8% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/event_trigger.out b/src/test/regress/expected/event_trigger.out index 065f586310f..ed8d5df397e 100644 --- a/src/test/regress/expected/event_trigger.out +++ b/src/test/regress/expected/event_trigger.out @@ -173,6 +173,23 @@ NOTICE: test_event_trigger: ddl_command_end CREATE USER MAPPING alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; NOTICE: test_event_trigger: ddl_command_end ALTER DEFAULT PRIVILEGES +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE TABLE t2x (i int PRIMARY KEY, j text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); +NOTICE: test_event_trigger: ddl_command_end CREATE PROPERTY GRAPH +DROP PROPERTY GRAPH gx; +NOTICE: test_event_trigger: ddl_command_end DROP PROPERTY GRAPH +DROP TABLE t1x, t2x; +NOTICE: test_event_trigger: ddl_command_end DROP TABLE -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; ERROR: permission denied to change owner of event trigger "regress_event_trigger" diff --git a/src/test/regress/expected/object_address.out b/src/test/regress/expected/object_address.out index 97227d67a54..729c3537f25 100644 --- a/src/test/regress/expected/object_address.out +++ b/src/test/regress/expected/object_address.out @@ -593,7 +593,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace @@ -653,6 +655,8 @@ ORDER BY objects.classid, objects.objid, objects.objsubid; ("(""parameter ACL"",,,)")|("(""parameter ACL"",,)")|NULL ("(""property graph element"",,,)")|("(""property graph element"",,)")|NULL ("(""property graph label"",,,)")|("(""property graph label"",,)")|NULL +("(""property graph element label"",,,)")|("(""property graph element label"",,)")|NULL ("(""property graph property"",,,)")|("(""property graph property"",,)")|NULL +("(""property graph label property"",,,)")|("(""property graph label property"",,)")|NULL -- restore normal output mode \a\t diff --git a/src/test/regress/sql/event_trigger.sql b/src/test/regress/sql/event_trigger.sql index 32e9bb58c5e..271f443378b 100644 --- a/src/test/regress/sql/event_trigger.sql +++ b/src/test/regress/sql/event_trigger.sql @@ -143,6 +143,19 @@ create user mapping for regress_evt_user server useless_server; alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +CREATE TABLE t2x (i int PRIMARY KEY, j text); + +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); + +DROP PROPERTY GRAPH gx; +DROP TABLE t1x, t2x; + -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; diff --git a/src/test/regress/sql/object_address.sql b/src/test/regress/sql/object_address.sql index 1bbe9457c1c..620dacf1045 100644 --- a/src/test/regress/sql/object_address.sql +++ b/src/test/regress/sql/object_address.sql @@ -282,7 +282,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace -- 2.34.1 --gtUR827Uq8d5gVsQ-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v3] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-23 09:27 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-23 09:27 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing them to hit the default case and error out with "unsupported object class". During DROP PROPERTY GRAPH, this manifests when an event trigger is active, because pg_event_trigger_ddl_commands() calls these functions. The same code paths are also reachable via pg_identify_object() and pg_identify_object_as_address(). This commit adds the missing cases. Test coverage is added in object_address.sql for these two catalog types and in create_property_graph.sql covering all property graph object types. A test in event_trigger.sql verifies that DROP PROPERTY GRAPH works correctly when an event trigger is active. Author: Bertrand Drouvot <[email protected]> Reviewed-by: Michael Paquier <[email protected]> Reviewed-by: Ashutosh Bapat <[email protected]> Discussion: https://postgr.es/m/aej1DkLwhyZWmtxJ@bdtpg --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 78 ++++++++++++++++ src/test/regress/expected/event_trigger.out | 17 ++++ src/test/regress/expected/object_address.out | 10 +- .../regress/sql/create_property_graph.sql | 23 +++++ src/test/regress/sql/event_trigger.sql | 13 +++ src/test/regress/sql/object_address.sql | 6 +- 7 files changed, 238 insertions(+), 2 deletions(-) 14.7% src/backend/catalog/ 75.5% src/test/regress/expected/ 9.7% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..eb9e17fb727 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -752,6 +752,84 @@ SELECT (pg_identify_object(classid, objid, objsubid)).* type | create_property_graph_tests | g2 | create_property_graph_tests.g2 (21 rows) +-- test object address functions with recursive dependency walk +-- covers all property graph object types including indirect dependents +SELECT * +FROM ( + WITH RECURSIVE deps (classid, objid, objsubid, refclassid, refobjid, refobjsubid) AS ( + SELECT classid, objid, objsubid, + refclassid, refobjid, refobjsubid + FROM pg_depend + WHERE refclassid = 'pg_class'::regclass AND + refobjid = 'create_property_graph_tests.gt'::regclass + UNION ALL + SELECT d.classid, d.objid, d.objsubid, + d.refclassid, d.refobjid, d.refobjsubid + FROM pg_depend d + JOIN deps dp ON d.refclassid = dp.classid AND d.refobjid = dp.objid AND d.refobjsubid = dp.objsubid + ) + SELECT pg_describe_object(classid, objid, objsubid) as obj, + pg_identify_object(classid, objid, objsubid) as ident, + pg_identify_object_as_address(classid, objid, objsubid) as addr + FROM deps +) s +ORDER BY obj COLLATE "C", ident::text COLLATE "C"; + obj | ident | addr +----------------------------------------------------------+----------------------------------------------------------------------------+---------------------------------------------------------------------------- + edge e of property graph gt | ("property graph element",,,"e of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,e}",{}) + edge e of property graph gt | ("property graph element",,,"e of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,e}",{}) + edge e of property graph gt | ("property graph element",,,"e of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of property graph gt | ("property graph label",,,"e of create_property_graph_tests.gt") | ("property graph label","{create_property_graph_tests,gt,e}",{}) + label v1 of property graph gt | ("property graph label",,,"v1 of create_property_graph_tests.gt") | ("property graph label","{create_property_graph_tests,gt,v1}",{}) + label v1 of vertex v1 of property graph gt | ("property graph element label",,,"v1 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v1}",{}) + label v1 of vertex v1 of property graph gt | ("property graph element label",,,"v1 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v1}",{}) + label v2 of property graph gt | ("property graph label",,,"v2 of create_property_graph_tests.gt") | ("property graph label","{create_property_graph_tests,gt,v2}",{}) + label v2 of vertex v2 of property graph gt | ("property graph element label",,,"v2 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v2}",{}) + label v2 of vertex v2 of property graph gt | ("property graph element label",,,"v2 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v2}",{}) + property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property a of property graph gt | ("property graph property",,,"a of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,a}",{}) + property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property b of property graph gt | ("property graph property",,,"b of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,b}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of property graph gt | ("property graph property",,,"c of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,c}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of property graph gt | ("property graph property",,,"k1 of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,k1}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of property graph gt | ("property graph property",,,"k2 of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,k2}",{}) + property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property m of property graph gt | ("property graph property",,,"m of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,m}",{}) + property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property n of property graph gt | ("property graph property",,,"n of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,n}",{}) + type gt | (type,create_property_graph_tests,gt,create_property_graph_tests.gt) | (type,{create_property_graph_tests.gt},{}) + type gt[] | (type,create_property_graph_tests,_gt,create_property_graph_tests.gt[]) | (type,{create_property_graph_tests.gt[]},{}) + vertex v1 of property graph gt | ("property graph element",,,"v1 of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,v1}",{}) + vertex v2 of property graph gt | ("property graph element",,,"v2 of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,v2}",{}) +(52 rows) + \a\t SELECT pg_get_propgraphdef('g2'::regclass); CREATE PROPERTY GRAPH create_property_graph_tests.g2 diff --git a/src/test/regress/expected/event_trigger.out b/src/test/regress/expected/event_trigger.out index 065f586310f..ed8d5df397e 100644 --- a/src/test/regress/expected/event_trigger.out +++ b/src/test/regress/expected/event_trigger.out @@ -173,6 +173,23 @@ NOTICE: test_event_trigger: ddl_command_end CREATE USER MAPPING alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; NOTICE: test_event_trigger: ddl_command_end ALTER DEFAULT PRIVILEGES +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE TABLE t2x (i int PRIMARY KEY, j text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); +NOTICE: test_event_trigger: ddl_command_end CREATE PROPERTY GRAPH +DROP PROPERTY GRAPH gx; +NOTICE: test_event_trigger: ddl_command_end DROP PROPERTY GRAPH +DROP TABLE t1x, t2x; +NOTICE: test_event_trigger: ddl_command_end DROP TABLE -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; ERROR: permission denied to change owner of event trigger "regress_event_trigger" diff --git a/src/test/regress/expected/object_address.out b/src/test/regress/expected/object_address.out index 97227d67a54..5e53f0b092e 100644 --- a/src/test/regress/expected/object_address.out +++ b/src/test/regress/expected/object_address.out @@ -67,7 +67,9 @@ DECLARE BEGIN FOR objtype IN VALUES ('toast table'), ('index column'), ('sequence column'), ('toast table column'), ('view column'), ('materialized view column'), - ('property graph element'), ('property graph label'), ('property graph property') + ('property graph element'), ('property graph element label'), + ('property graph label'), ('property graph label property'), + ('property graph property') LOOP BEGIN PERFORM pg_get_object_address(objtype, '{one}', '{}'); @@ -84,7 +86,9 @@ WARNING: error for toast table column: unsupported object type "toast table col WARNING: error for view column: unsupported object type "view column" WARNING: error for materialized view column: unsupported object type "materialized view column" WARNING: error for property graph element: unsupported object type "property graph element" +WARNING: error for property graph element label: unrecognized object type "property graph element label" WARNING: error for property graph label: unsupported object type "property graph label" +WARNING: error for property graph label property: unrecognized object type "property graph label property" WARNING: error for property graph property: unsupported object type "property graph property" -- miscellaneous other errors select * from pg_get_object_address('operator of access method', '{btree,integer_ops,1}', '{int4,bool}'); @@ -593,7 +597,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace @@ -653,6 +659,8 @@ ORDER BY objects.classid, objects.objid, objects.objsubid; ("(""parameter ACL"",,,)")|("(""parameter ACL"",,)")|NULL ("(""property graph element"",,,)")|("(""property graph element"",,)")|NULL ("(""property graph label"",,,)")|("(""property graph label"",,)")|NULL +("(""property graph element label"",,,)")|("(""property graph element label"",,)")|NULL ("(""property graph property"",,,)")|("(""property graph property"",,)")|NULL +("(""property graph label property"",,,)")|("(""property graph label property"",,)")|NULL -- restore normal output mode \a\t diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..9608dd5c4af 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -298,6 +298,29 @@ SELECT (pg_identify_object(classid, objid, objsubid)).* refobjid = 'create_property_graph_tests.g2'::regclass ORDER BY 1, 2, 3, 4; +-- test object address functions with recursive dependency walk +-- covers all property graph object types including indirect dependents +SELECT * +FROM ( + WITH RECURSIVE deps (classid, objid, objsubid, refclassid, refobjid, refobjsubid) AS ( + SELECT classid, objid, objsubid, + refclassid, refobjid, refobjsubid + FROM pg_depend + WHERE refclassid = 'pg_class'::regclass AND + refobjid = 'create_property_graph_tests.gt'::regclass + UNION ALL + SELECT d.classid, d.objid, d.objsubid, + d.refclassid, d.refobjid, d.refobjsubid + FROM pg_depend d + JOIN deps dp ON d.refclassid = dp.classid AND d.refobjid = dp.objid AND d.refobjsubid = dp.objsubid + ) + SELECT pg_describe_object(classid, objid, objsubid) as obj, + pg_identify_object(classid, objid, objsubid) as ident, + pg_identify_object_as_address(classid, objid, objsubid) as addr + FROM deps +) s +ORDER BY obj COLLATE "C", ident::text COLLATE "C"; + \a\t SELECT pg_get_propgraphdef('g2'::regclass); SELECT pg_get_propgraphdef('g3'::regclass); diff --git a/src/test/regress/sql/event_trigger.sql b/src/test/regress/sql/event_trigger.sql index 32e9bb58c5e..271f443378b 100644 --- a/src/test/regress/sql/event_trigger.sql +++ b/src/test/regress/sql/event_trigger.sql @@ -143,6 +143,19 @@ create user mapping for regress_evt_user server useless_server; alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +CREATE TABLE t2x (i int PRIMARY KEY, j text); + +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); + +DROP PROPERTY GRAPH gx; +DROP TABLE t1x, t2x; + -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; diff --git a/src/test/regress/sql/object_address.sql b/src/test/regress/sql/object_address.sql index 1bbe9457c1c..27109d421c7 100644 --- a/src/test/regress/sql/object_address.sql +++ b/src/test/regress/sql/object_address.sql @@ -67,7 +67,9 @@ DECLARE BEGIN FOR objtype IN VALUES ('toast table'), ('index column'), ('sequence column'), ('toast table column'), ('view column'), ('materialized view column'), - ('property graph element'), ('property graph label'), ('property graph property') + ('property graph element'), ('property graph element label'), + ('property graph label'), ('property graph label property'), + ('property graph property') LOOP BEGIN PERFORM pg_get_object_address(objtype, '{one}', '{}'); @@ -282,7 +284,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace -- 2.34.1 --R84XrR4Hgw0dH3Ec-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v2] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-23 09:27 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-23 09:27 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing them to hit the default case and error out with "unsupported object class". During DROP PROPERTY GRAPH, this manifests when an event trigger is active, because pg_event_trigger_ddl_commands() calls these functions. The same code paths are also reachable via pg_identify_object() and pg_identify_object_as_address(). This commit adds the missing cases. Test coverage is added in object_address.sql for these two catalog types via the zero-OID test that exercises pg_identify_object() and pg_identify_object_as_address(). A test in event_trigger.sql verifies that DROP PROPERTY GRAPH works correctly when an event trigger is active. Author: Bertrand Drouvot <[email protected]> Reviewed-by: Michael Paquier <[email protected]> Reviewed-by: Ashutosh Bapat <[email protected]> Discussion: https://postgr.es/m/aej1DkLwhyZWmtxJ@bdtpg --- src/backend/catalog/objectaddress.c | 93 ++++++++++++++++++++ src/test/regress/expected/event_trigger.out | 17 ++++ src/test/regress/expected/object_address.out | 4 + src/test/regress/sql/event_trigger.sql | 13 +++ src/test/regress/sql/object_address.sql | 2 + 5 files changed, 129 insertions(+) 62.4% src/backend/catalog/ 25.6% src/test/regress/expected/ 11.8% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/event_trigger.out b/src/test/regress/expected/event_trigger.out index 065f586310f..ed8d5df397e 100644 --- a/src/test/regress/expected/event_trigger.out +++ b/src/test/regress/expected/event_trigger.out @@ -173,6 +173,23 @@ NOTICE: test_event_trigger: ddl_command_end CREATE USER MAPPING alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; NOTICE: test_event_trigger: ddl_command_end ALTER DEFAULT PRIVILEGES +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE TABLE t2x (i int PRIMARY KEY, j text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); +NOTICE: test_event_trigger: ddl_command_end CREATE PROPERTY GRAPH +DROP PROPERTY GRAPH gx; +NOTICE: test_event_trigger: ddl_command_end DROP PROPERTY GRAPH +DROP TABLE t1x, t2x; +NOTICE: test_event_trigger: ddl_command_end DROP TABLE -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; ERROR: permission denied to change owner of event trigger "regress_event_trigger" diff --git a/src/test/regress/expected/object_address.out b/src/test/regress/expected/object_address.out index 97227d67a54..729c3537f25 100644 --- a/src/test/regress/expected/object_address.out +++ b/src/test/regress/expected/object_address.out @@ -593,7 +593,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace @@ -653,6 +655,8 @@ ORDER BY objects.classid, objects.objid, objects.objsubid; ("(""parameter ACL"",,,)")|("(""parameter ACL"",,)")|NULL ("(""property graph element"",,,)")|("(""property graph element"",,)")|NULL ("(""property graph label"",,,)")|("(""property graph label"",,)")|NULL +("(""property graph element label"",,,)")|("(""property graph element label"",,)")|NULL ("(""property graph property"",,,)")|("(""property graph property"",,)")|NULL +("(""property graph label property"",,,)")|("(""property graph label property"",,)")|NULL -- restore normal output mode \a\t diff --git a/src/test/regress/sql/event_trigger.sql b/src/test/regress/sql/event_trigger.sql index 32e9bb58c5e..271f443378b 100644 --- a/src/test/regress/sql/event_trigger.sql +++ b/src/test/regress/sql/event_trigger.sql @@ -143,6 +143,19 @@ create user mapping for regress_evt_user server useless_server; alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +CREATE TABLE t2x (i int PRIMARY KEY, j text); + +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); + +DROP PROPERTY GRAPH gx; +DROP TABLE t1x, t2x; + -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; diff --git a/src/test/regress/sql/object_address.sql b/src/test/regress/sql/object_address.sql index 1bbe9457c1c..620dacf1045 100644 --- a/src/test/regress/sql/object_address.sql +++ b/src/test/regress/sql/object_address.sql @@ -282,7 +282,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace -- 2.34.1 --gtUR827Uq8d5gVsQ-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v3] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-23 09:27 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-23 09:27 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing them to hit the default case and error out with "unsupported object class". During DROP PROPERTY GRAPH, this manifests when an event trigger is active, because pg_event_trigger_ddl_commands() calls these functions. The same code paths are also reachable via pg_identify_object() and pg_identify_object_as_address(). This commit adds the missing cases. Test coverage is added in object_address.sql for these two catalog types and in create_property_graph.sql covering all property graph object types. A test in event_trigger.sql verifies that DROP PROPERTY GRAPH works correctly when an event trigger is active. Author: Bertrand Drouvot <[email protected]> Reviewed-by: Michael Paquier <[email protected]> Reviewed-by: Ashutosh Bapat <[email protected]> Discussion: https://postgr.es/m/aej1DkLwhyZWmtxJ@bdtpg --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 78 ++++++++++++++++ src/test/regress/expected/event_trigger.out | 17 ++++ src/test/regress/expected/object_address.out | 10 +- .../regress/sql/create_property_graph.sql | 23 +++++ src/test/regress/sql/event_trigger.sql | 13 +++ src/test/regress/sql/object_address.sql | 6 +- 7 files changed, 238 insertions(+), 2 deletions(-) 14.7% src/backend/catalog/ 75.5% src/test/regress/expected/ 9.7% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..eb9e17fb727 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -752,6 +752,84 @@ SELECT (pg_identify_object(classid, objid, objsubid)).* type | create_property_graph_tests | g2 | create_property_graph_tests.g2 (21 rows) +-- test object address functions with recursive dependency walk +-- covers all property graph object types including indirect dependents +SELECT * +FROM ( + WITH RECURSIVE deps (classid, objid, objsubid, refclassid, refobjid, refobjsubid) AS ( + SELECT classid, objid, objsubid, + refclassid, refobjid, refobjsubid + FROM pg_depend + WHERE refclassid = 'pg_class'::regclass AND + refobjid = 'create_property_graph_tests.gt'::regclass + UNION ALL + SELECT d.classid, d.objid, d.objsubid, + d.refclassid, d.refobjid, d.refobjsubid + FROM pg_depend d + JOIN deps dp ON d.refclassid = dp.classid AND d.refobjid = dp.objid AND d.refobjsubid = dp.objsubid + ) + SELECT pg_describe_object(classid, objid, objsubid) as obj, + pg_identify_object(classid, objid, objsubid) as ident, + pg_identify_object_as_address(classid, objid, objsubid) as addr + FROM deps +) s +ORDER BY obj COLLATE "C", ident::text COLLATE "C"; + obj | ident | addr +----------------------------------------------------------+----------------------------------------------------------------------------+---------------------------------------------------------------------------- + edge e of property graph gt | ("property graph element",,,"e of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,e}",{}) + edge e of property graph gt | ("property graph element",,,"e of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,e}",{}) + edge e of property graph gt | ("property graph element",,,"e of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of property graph gt | ("property graph label",,,"e of create_property_graph_tests.gt") | ("property graph label","{create_property_graph_tests,gt,e}",{}) + label v1 of property graph gt | ("property graph label",,,"v1 of create_property_graph_tests.gt") | ("property graph label","{create_property_graph_tests,gt,v1}",{}) + label v1 of vertex v1 of property graph gt | ("property graph element label",,,"v1 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v1}",{}) + label v1 of vertex v1 of property graph gt | ("property graph element label",,,"v1 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v1}",{}) + label v2 of property graph gt | ("property graph label",,,"v2 of create_property_graph_tests.gt") | ("property graph label","{create_property_graph_tests,gt,v2}",{}) + label v2 of vertex v2 of property graph gt | ("property graph element label",,,"v2 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v2}",{}) + label v2 of vertex v2 of property graph gt | ("property graph element label",,,"v2 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v2}",{}) + property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property a of property graph gt | ("property graph property",,,"a of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,a}",{}) + property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property b of property graph gt | ("property graph property",,,"b of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,b}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of property graph gt | ("property graph property",,,"c of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,c}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of property graph gt | ("property graph property",,,"k1 of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,k1}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of property graph gt | ("property graph property",,,"k2 of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,k2}",{}) + property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property m of property graph gt | ("property graph property",,,"m of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,m}",{}) + property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property n of property graph gt | ("property graph property",,,"n of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,n}",{}) + type gt | (type,create_property_graph_tests,gt,create_property_graph_tests.gt) | (type,{create_property_graph_tests.gt},{}) + type gt[] | (type,create_property_graph_tests,_gt,create_property_graph_tests.gt[]) | (type,{create_property_graph_tests.gt[]},{}) + vertex v1 of property graph gt | ("property graph element",,,"v1 of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,v1}",{}) + vertex v2 of property graph gt | ("property graph element",,,"v2 of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,v2}",{}) +(52 rows) + \a\t SELECT pg_get_propgraphdef('g2'::regclass); CREATE PROPERTY GRAPH create_property_graph_tests.g2 diff --git a/src/test/regress/expected/event_trigger.out b/src/test/regress/expected/event_trigger.out index 065f586310f..ed8d5df397e 100644 --- a/src/test/regress/expected/event_trigger.out +++ b/src/test/regress/expected/event_trigger.out @@ -173,6 +173,23 @@ NOTICE: test_event_trigger: ddl_command_end CREATE USER MAPPING alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; NOTICE: test_event_trigger: ddl_command_end ALTER DEFAULT PRIVILEGES +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE TABLE t2x (i int PRIMARY KEY, j text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); +NOTICE: test_event_trigger: ddl_command_end CREATE PROPERTY GRAPH +DROP PROPERTY GRAPH gx; +NOTICE: test_event_trigger: ddl_command_end DROP PROPERTY GRAPH +DROP TABLE t1x, t2x; +NOTICE: test_event_trigger: ddl_command_end DROP TABLE -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; ERROR: permission denied to change owner of event trigger "regress_event_trigger" diff --git a/src/test/regress/expected/object_address.out b/src/test/regress/expected/object_address.out index 97227d67a54..5e53f0b092e 100644 --- a/src/test/regress/expected/object_address.out +++ b/src/test/regress/expected/object_address.out @@ -67,7 +67,9 @@ DECLARE BEGIN FOR objtype IN VALUES ('toast table'), ('index column'), ('sequence column'), ('toast table column'), ('view column'), ('materialized view column'), - ('property graph element'), ('property graph label'), ('property graph property') + ('property graph element'), ('property graph element label'), + ('property graph label'), ('property graph label property'), + ('property graph property') LOOP BEGIN PERFORM pg_get_object_address(objtype, '{one}', '{}'); @@ -84,7 +86,9 @@ WARNING: error for toast table column: unsupported object type "toast table col WARNING: error for view column: unsupported object type "view column" WARNING: error for materialized view column: unsupported object type "materialized view column" WARNING: error for property graph element: unsupported object type "property graph element" +WARNING: error for property graph element label: unrecognized object type "property graph element label" WARNING: error for property graph label: unsupported object type "property graph label" +WARNING: error for property graph label property: unrecognized object type "property graph label property" WARNING: error for property graph property: unsupported object type "property graph property" -- miscellaneous other errors select * from pg_get_object_address('operator of access method', '{btree,integer_ops,1}', '{int4,bool}'); @@ -593,7 +597,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace @@ -653,6 +659,8 @@ ORDER BY objects.classid, objects.objid, objects.objsubid; ("(""parameter ACL"",,,)")|("(""parameter ACL"",,)")|NULL ("(""property graph element"",,,)")|("(""property graph element"",,)")|NULL ("(""property graph label"",,,)")|("(""property graph label"",,)")|NULL +("(""property graph element label"",,,)")|("(""property graph element label"",,)")|NULL ("(""property graph property"",,,)")|("(""property graph property"",,)")|NULL +("(""property graph label property"",,,)")|("(""property graph label property"",,)")|NULL -- restore normal output mode \a\t diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..9608dd5c4af 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -298,6 +298,29 @@ SELECT (pg_identify_object(classid, objid, objsubid)).* refobjid = 'create_property_graph_tests.g2'::regclass ORDER BY 1, 2, 3, 4; +-- test object address functions with recursive dependency walk +-- covers all property graph object types including indirect dependents +SELECT * +FROM ( + WITH RECURSIVE deps (classid, objid, objsubid, refclassid, refobjid, refobjsubid) AS ( + SELECT classid, objid, objsubid, + refclassid, refobjid, refobjsubid + FROM pg_depend + WHERE refclassid = 'pg_class'::regclass AND + refobjid = 'create_property_graph_tests.gt'::regclass + UNION ALL + SELECT d.classid, d.objid, d.objsubid, + d.refclassid, d.refobjid, d.refobjsubid + FROM pg_depend d + JOIN deps dp ON d.refclassid = dp.classid AND d.refobjid = dp.objid AND d.refobjsubid = dp.objsubid + ) + SELECT pg_describe_object(classid, objid, objsubid) as obj, + pg_identify_object(classid, objid, objsubid) as ident, + pg_identify_object_as_address(classid, objid, objsubid) as addr + FROM deps +) s +ORDER BY obj COLLATE "C", ident::text COLLATE "C"; + \a\t SELECT pg_get_propgraphdef('g2'::regclass); SELECT pg_get_propgraphdef('g3'::regclass); diff --git a/src/test/regress/sql/event_trigger.sql b/src/test/regress/sql/event_trigger.sql index 32e9bb58c5e..271f443378b 100644 --- a/src/test/regress/sql/event_trigger.sql +++ b/src/test/regress/sql/event_trigger.sql @@ -143,6 +143,19 @@ create user mapping for regress_evt_user server useless_server; alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +CREATE TABLE t2x (i int PRIMARY KEY, j text); + +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); + +DROP PROPERTY GRAPH gx; +DROP TABLE t1x, t2x; + -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; diff --git a/src/test/regress/sql/object_address.sql b/src/test/regress/sql/object_address.sql index 1bbe9457c1c..27109d421c7 100644 --- a/src/test/regress/sql/object_address.sql +++ b/src/test/regress/sql/object_address.sql @@ -67,7 +67,9 @@ DECLARE BEGIN FOR objtype IN VALUES ('toast table'), ('index column'), ('sequence column'), ('toast table column'), ('view column'), ('materialized view column'), - ('property graph element'), ('property graph label'), ('property graph property') + ('property graph element'), ('property graph element label'), + ('property graph label'), ('property graph label property'), + ('property graph property') LOOP BEGIN PERFORM pg_get_object_address(objtype, '{one}', '{}'); @@ -282,7 +284,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace -- 2.34.1 --R84XrR4Hgw0dH3Ec-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v3] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-23 09:27 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-23 09:27 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing them to hit the default case and error out with "unsupported object class". During DROP PROPERTY GRAPH, this manifests when an event trigger is active, because pg_event_trigger_ddl_commands() calls these functions. The same code paths are also reachable via pg_identify_object() and pg_identify_object_as_address(). This commit adds the missing cases. Test coverage is added in object_address.sql for these two catalog types and in create_property_graph.sql covering all property graph object types. A test in event_trigger.sql verifies that DROP PROPERTY GRAPH works correctly when an event trigger is active. Author: Bertrand Drouvot <[email protected]> Reviewed-by: Michael Paquier <[email protected]> Reviewed-by: Ashutosh Bapat <[email protected]> Discussion: https://postgr.es/m/aej1DkLwhyZWmtxJ@bdtpg --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 78 ++++++++++++++++ src/test/regress/expected/event_trigger.out | 17 ++++ src/test/regress/expected/object_address.out | 10 +- .../regress/sql/create_property_graph.sql | 23 +++++ src/test/regress/sql/event_trigger.sql | 13 +++ src/test/regress/sql/object_address.sql | 6 +- 7 files changed, 238 insertions(+), 2 deletions(-) 14.7% src/backend/catalog/ 75.5% src/test/regress/expected/ 9.7% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..eb9e17fb727 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -752,6 +752,84 @@ SELECT (pg_identify_object(classid, objid, objsubid)).* type | create_property_graph_tests | g2 | create_property_graph_tests.g2 (21 rows) +-- test object address functions with recursive dependency walk +-- covers all property graph object types including indirect dependents +SELECT * +FROM ( + WITH RECURSIVE deps (classid, objid, objsubid, refclassid, refobjid, refobjsubid) AS ( + SELECT classid, objid, objsubid, + refclassid, refobjid, refobjsubid + FROM pg_depend + WHERE refclassid = 'pg_class'::regclass AND + refobjid = 'create_property_graph_tests.gt'::regclass + UNION ALL + SELECT d.classid, d.objid, d.objsubid, + d.refclassid, d.refobjid, d.refobjsubid + FROM pg_depend d + JOIN deps dp ON d.refclassid = dp.classid AND d.refobjid = dp.objid AND d.refobjsubid = dp.objsubid + ) + SELECT pg_describe_object(classid, objid, objsubid) as obj, + pg_identify_object(classid, objid, objsubid) as ident, + pg_identify_object_as_address(classid, objid, objsubid) as addr + FROM deps +) s +ORDER BY obj COLLATE "C", ident::text COLLATE "C"; + obj | ident | addr +----------------------------------------------------------+----------------------------------------------------------------------------+---------------------------------------------------------------------------- + edge e of property graph gt | ("property graph element",,,"e of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,e}",{}) + edge e of property graph gt | ("property graph element",,,"e of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,e}",{}) + edge e of property graph gt | ("property graph element",,,"e of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of property graph gt | ("property graph label",,,"e of create_property_graph_tests.gt") | ("property graph label","{create_property_graph_tests,gt,e}",{}) + label v1 of property graph gt | ("property graph label",,,"v1 of create_property_graph_tests.gt") | ("property graph label","{create_property_graph_tests,gt,v1}",{}) + label v1 of vertex v1 of property graph gt | ("property graph element label",,,"v1 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v1}",{}) + label v1 of vertex v1 of property graph gt | ("property graph element label",,,"v1 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v1}",{}) + label v2 of property graph gt | ("property graph label",,,"v2 of create_property_graph_tests.gt") | ("property graph label","{create_property_graph_tests,gt,v2}",{}) + label v2 of vertex v2 of property graph gt | ("property graph element label",,,"v2 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v2}",{}) + label v2 of vertex v2 of property graph gt | ("property graph element label",,,"v2 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v2}",{}) + property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property a of property graph gt | ("property graph property",,,"a of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,a}",{}) + property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property b of property graph gt | ("property graph property",,,"b of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,b}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of property graph gt | ("property graph property",,,"c of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,c}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of property graph gt | ("property graph property",,,"k1 of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,k1}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of property graph gt | ("property graph property",,,"k2 of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,k2}",{}) + property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property m of property graph gt | ("property graph property",,,"m of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,m}",{}) + property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property n of property graph gt | ("property graph property",,,"n of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,n}",{}) + type gt | (type,create_property_graph_tests,gt,create_property_graph_tests.gt) | (type,{create_property_graph_tests.gt},{}) + type gt[] | (type,create_property_graph_tests,_gt,create_property_graph_tests.gt[]) | (type,{create_property_graph_tests.gt[]},{}) + vertex v1 of property graph gt | ("property graph element",,,"v1 of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,v1}",{}) + vertex v2 of property graph gt | ("property graph element",,,"v2 of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,v2}",{}) +(52 rows) + \a\t SELECT pg_get_propgraphdef('g2'::regclass); CREATE PROPERTY GRAPH create_property_graph_tests.g2 diff --git a/src/test/regress/expected/event_trigger.out b/src/test/regress/expected/event_trigger.out index 065f586310f..ed8d5df397e 100644 --- a/src/test/regress/expected/event_trigger.out +++ b/src/test/regress/expected/event_trigger.out @@ -173,6 +173,23 @@ NOTICE: test_event_trigger: ddl_command_end CREATE USER MAPPING alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; NOTICE: test_event_trigger: ddl_command_end ALTER DEFAULT PRIVILEGES +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE TABLE t2x (i int PRIMARY KEY, j text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); +NOTICE: test_event_trigger: ddl_command_end CREATE PROPERTY GRAPH +DROP PROPERTY GRAPH gx; +NOTICE: test_event_trigger: ddl_command_end DROP PROPERTY GRAPH +DROP TABLE t1x, t2x; +NOTICE: test_event_trigger: ddl_command_end DROP TABLE -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; ERROR: permission denied to change owner of event trigger "regress_event_trigger" diff --git a/src/test/regress/expected/object_address.out b/src/test/regress/expected/object_address.out index 97227d67a54..5e53f0b092e 100644 --- a/src/test/regress/expected/object_address.out +++ b/src/test/regress/expected/object_address.out @@ -67,7 +67,9 @@ DECLARE BEGIN FOR objtype IN VALUES ('toast table'), ('index column'), ('sequence column'), ('toast table column'), ('view column'), ('materialized view column'), - ('property graph element'), ('property graph label'), ('property graph property') + ('property graph element'), ('property graph element label'), + ('property graph label'), ('property graph label property'), + ('property graph property') LOOP BEGIN PERFORM pg_get_object_address(objtype, '{one}', '{}'); @@ -84,7 +86,9 @@ WARNING: error for toast table column: unsupported object type "toast table col WARNING: error for view column: unsupported object type "view column" WARNING: error for materialized view column: unsupported object type "materialized view column" WARNING: error for property graph element: unsupported object type "property graph element" +WARNING: error for property graph element label: unrecognized object type "property graph element label" WARNING: error for property graph label: unsupported object type "property graph label" +WARNING: error for property graph label property: unrecognized object type "property graph label property" WARNING: error for property graph property: unsupported object type "property graph property" -- miscellaneous other errors select * from pg_get_object_address('operator of access method', '{btree,integer_ops,1}', '{int4,bool}'); @@ -593,7 +597,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace @@ -653,6 +659,8 @@ ORDER BY objects.classid, objects.objid, objects.objsubid; ("(""parameter ACL"",,,)")|("(""parameter ACL"",,)")|NULL ("(""property graph element"",,,)")|("(""property graph element"",,)")|NULL ("(""property graph label"",,,)")|("(""property graph label"",,)")|NULL +("(""property graph element label"",,,)")|("(""property graph element label"",,)")|NULL ("(""property graph property"",,,)")|("(""property graph property"",,)")|NULL +("(""property graph label property"",,,)")|("(""property graph label property"",,)")|NULL -- restore normal output mode \a\t diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..9608dd5c4af 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -298,6 +298,29 @@ SELECT (pg_identify_object(classid, objid, objsubid)).* refobjid = 'create_property_graph_tests.g2'::regclass ORDER BY 1, 2, 3, 4; +-- test object address functions with recursive dependency walk +-- covers all property graph object types including indirect dependents +SELECT * +FROM ( + WITH RECURSIVE deps (classid, objid, objsubid, refclassid, refobjid, refobjsubid) AS ( + SELECT classid, objid, objsubid, + refclassid, refobjid, refobjsubid + FROM pg_depend + WHERE refclassid = 'pg_class'::regclass AND + refobjid = 'create_property_graph_tests.gt'::regclass + UNION ALL + SELECT d.classid, d.objid, d.objsubid, + d.refclassid, d.refobjid, d.refobjsubid + FROM pg_depend d + JOIN deps dp ON d.refclassid = dp.classid AND d.refobjid = dp.objid AND d.refobjsubid = dp.objsubid + ) + SELECT pg_describe_object(classid, objid, objsubid) as obj, + pg_identify_object(classid, objid, objsubid) as ident, + pg_identify_object_as_address(classid, objid, objsubid) as addr + FROM deps +) s +ORDER BY obj COLLATE "C", ident::text COLLATE "C"; + \a\t SELECT pg_get_propgraphdef('g2'::regclass); SELECT pg_get_propgraphdef('g3'::regclass); diff --git a/src/test/regress/sql/event_trigger.sql b/src/test/regress/sql/event_trigger.sql index 32e9bb58c5e..271f443378b 100644 --- a/src/test/regress/sql/event_trigger.sql +++ b/src/test/regress/sql/event_trigger.sql @@ -143,6 +143,19 @@ create user mapping for regress_evt_user server useless_server; alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +CREATE TABLE t2x (i int PRIMARY KEY, j text); + +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); + +DROP PROPERTY GRAPH gx; +DROP TABLE t1x, t2x; + -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; diff --git a/src/test/regress/sql/object_address.sql b/src/test/regress/sql/object_address.sql index 1bbe9457c1c..27109d421c7 100644 --- a/src/test/regress/sql/object_address.sql +++ b/src/test/regress/sql/object_address.sql @@ -67,7 +67,9 @@ DECLARE BEGIN FOR objtype IN VALUES ('toast table'), ('index column'), ('sequence column'), ('toast table column'), ('view column'), ('materialized view column'), - ('property graph element'), ('property graph label'), ('property graph property') + ('property graph element'), ('property graph element label'), + ('property graph label'), ('property graph label property'), + ('property graph property') LOOP BEGIN PERFORM pg_get_object_address(objtype, '{one}', '{}'); @@ -282,7 +284,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace -- 2.34.1 --R84XrR4Hgw0dH3Ec-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v3] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-23 09:27 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-23 09:27 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing them to hit the default case and error out with "unsupported object class". During DROP PROPERTY GRAPH, this manifests when an event trigger is active, because pg_event_trigger_ddl_commands() calls these functions. The same code paths are also reachable via pg_identify_object() and pg_identify_object_as_address(). This commit adds the missing cases. Test coverage is added in object_address.sql for these two catalog types and in create_property_graph.sql covering all property graph object types. A test in event_trigger.sql verifies that DROP PROPERTY GRAPH works correctly when an event trigger is active. Author: Bertrand Drouvot <[email protected]> Reviewed-by: Michael Paquier <[email protected]> Reviewed-by: Ashutosh Bapat <[email protected]> Discussion: https://postgr.es/m/aej1DkLwhyZWmtxJ@bdtpg --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 78 ++++++++++++++++ src/test/regress/expected/event_trigger.out | 17 ++++ src/test/regress/expected/object_address.out | 10 +- .../regress/sql/create_property_graph.sql | 23 +++++ src/test/regress/sql/event_trigger.sql | 13 +++ src/test/regress/sql/object_address.sql | 6 +- 7 files changed, 238 insertions(+), 2 deletions(-) 14.7% src/backend/catalog/ 75.5% src/test/regress/expected/ 9.7% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..eb9e17fb727 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -752,6 +752,84 @@ SELECT (pg_identify_object(classid, objid, objsubid)).* type | create_property_graph_tests | g2 | create_property_graph_tests.g2 (21 rows) +-- test object address functions with recursive dependency walk +-- covers all property graph object types including indirect dependents +SELECT * +FROM ( + WITH RECURSIVE deps (classid, objid, objsubid, refclassid, refobjid, refobjsubid) AS ( + SELECT classid, objid, objsubid, + refclassid, refobjid, refobjsubid + FROM pg_depend + WHERE refclassid = 'pg_class'::regclass AND + refobjid = 'create_property_graph_tests.gt'::regclass + UNION ALL + SELECT d.classid, d.objid, d.objsubid, + d.refclassid, d.refobjid, d.refobjsubid + FROM pg_depend d + JOIN deps dp ON d.refclassid = dp.classid AND d.refobjid = dp.objid AND d.refobjsubid = dp.objsubid + ) + SELECT pg_describe_object(classid, objid, objsubid) as obj, + pg_identify_object(classid, objid, objsubid) as ident, + pg_identify_object_as_address(classid, objid, objsubid) as addr + FROM deps +) s +ORDER BY obj COLLATE "C", ident::text COLLATE "C"; + obj | ident | addr +----------------------------------------------------------+----------------------------------------------------------------------------+---------------------------------------------------------------------------- + edge e of property graph gt | ("property graph element",,,"e of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,e}",{}) + edge e of property graph gt | ("property graph element",,,"e of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,e}",{}) + edge e of property graph gt | ("property graph element",,,"e of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of property graph gt | ("property graph label",,,"e of create_property_graph_tests.gt") | ("property graph label","{create_property_graph_tests,gt,e}",{}) + label v1 of property graph gt | ("property graph label",,,"v1 of create_property_graph_tests.gt") | ("property graph label","{create_property_graph_tests,gt,v1}",{}) + label v1 of vertex v1 of property graph gt | ("property graph element label",,,"v1 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v1}",{}) + label v1 of vertex v1 of property graph gt | ("property graph element label",,,"v1 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v1}",{}) + label v2 of property graph gt | ("property graph label",,,"v2 of create_property_graph_tests.gt") | ("property graph label","{create_property_graph_tests,gt,v2}",{}) + label v2 of vertex v2 of property graph gt | ("property graph element label",,,"v2 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v2}",{}) + label v2 of vertex v2 of property graph gt | ("property graph element label",,,"v2 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v2}",{}) + property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property a of property graph gt | ("property graph property",,,"a of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,a}",{}) + property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property b of property graph gt | ("property graph property",,,"b of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,b}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of property graph gt | ("property graph property",,,"c of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,c}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of property graph gt | ("property graph property",,,"k1 of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,k1}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of property graph gt | ("property graph property",,,"k2 of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,k2}",{}) + property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property m of property graph gt | ("property graph property",,,"m of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,m}",{}) + property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property n of property graph gt | ("property graph property",,,"n of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,n}",{}) + type gt | (type,create_property_graph_tests,gt,create_property_graph_tests.gt) | (type,{create_property_graph_tests.gt},{}) + type gt[] | (type,create_property_graph_tests,_gt,create_property_graph_tests.gt[]) | (type,{create_property_graph_tests.gt[]},{}) + vertex v1 of property graph gt | ("property graph element",,,"v1 of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,v1}",{}) + vertex v2 of property graph gt | ("property graph element",,,"v2 of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,v2}",{}) +(52 rows) + \a\t SELECT pg_get_propgraphdef('g2'::regclass); CREATE PROPERTY GRAPH create_property_graph_tests.g2 diff --git a/src/test/regress/expected/event_trigger.out b/src/test/regress/expected/event_trigger.out index 065f586310f..ed8d5df397e 100644 --- a/src/test/regress/expected/event_trigger.out +++ b/src/test/regress/expected/event_trigger.out @@ -173,6 +173,23 @@ NOTICE: test_event_trigger: ddl_command_end CREATE USER MAPPING alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; NOTICE: test_event_trigger: ddl_command_end ALTER DEFAULT PRIVILEGES +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE TABLE t2x (i int PRIMARY KEY, j text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); +NOTICE: test_event_trigger: ddl_command_end CREATE PROPERTY GRAPH +DROP PROPERTY GRAPH gx; +NOTICE: test_event_trigger: ddl_command_end DROP PROPERTY GRAPH +DROP TABLE t1x, t2x; +NOTICE: test_event_trigger: ddl_command_end DROP TABLE -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; ERROR: permission denied to change owner of event trigger "regress_event_trigger" diff --git a/src/test/regress/expected/object_address.out b/src/test/regress/expected/object_address.out index 97227d67a54..5e53f0b092e 100644 --- a/src/test/regress/expected/object_address.out +++ b/src/test/regress/expected/object_address.out @@ -67,7 +67,9 @@ DECLARE BEGIN FOR objtype IN VALUES ('toast table'), ('index column'), ('sequence column'), ('toast table column'), ('view column'), ('materialized view column'), - ('property graph element'), ('property graph label'), ('property graph property') + ('property graph element'), ('property graph element label'), + ('property graph label'), ('property graph label property'), + ('property graph property') LOOP BEGIN PERFORM pg_get_object_address(objtype, '{one}', '{}'); @@ -84,7 +86,9 @@ WARNING: error for toast table column: unsupported object type "toast table col WARNING: error for view column: unsupported object type "view column" WARNING: error for materialized view column: unsupported object type "materialized view column" WARNING: error for property graph element: unsupported object type "property graph element" +WARNING: error for property graph element label: unrecognized object type "property graph element label" WARNING: error for property graph label: unsupported object type "property graph label" +WARNING: error for property graph label property: unrecognized object type "property graph label property" WARNING: error for property graph property: unsupported object type "property graph property" -- miscellaneous other errors select * from pg_get_object_address('operator of access method', '{btree,integer_ops,1}', '{int4,bool}'); @@ -593,7 +597,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace @@ -653,6 +659,8 @@ ORDER BY objects.classid, objects.objid, objects.objsubid; ("(""parameter ACL"",,,)")|("(""parameter ACL"",,)")|NULL ("(""property graph element"",,,)")|("(""property graph element"",,)")|NULL ("(""property graph label"",,,)")|("(""property graph label"",,)")|NULL +("(""property graph element label"",,,)")|("(""property graph element label"",,)")|NULL ("(""property graph property"",,,)")|("(""property graph property"",,)")|NULL +("(""property graph label property"",,,)")|("(""property graph label property"",,)")|NULL -- restore normal output mode \a\t diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..9608dd5c4af 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -298,6 +298,29 @@ SELECT (pg_identify_object(classid, objid, objsubid)).* refobjid = 'create_property_graph_tests.g2'::regclass ORDER BY 1, 2, 3, 4; +-- test object address functions with recursive dependency walk +-- covers all property graph object types including indirect dependents +SELECT * +FROM ( + WITH RECURSIVE deps (classid, objid, objsubid, refclassid, refobjid, refobjsubid) AS ( + SELECT classid, objid, objsubid, + refclassid, refobjid, refobjsubid + FROM pg_depend + WHERE refclassid = 'pg_class'::regclass AND + refobjid = 'create_property_graph_tests.gt'::regclass + UNION ALL + SELECT d.classid, d.objid, d.objsubid, + d.refclassid, d.refobjid, d.refobjsubid + FROM pg_depend d + JOIN deps dp ON d.refclassid = dp.classid AND d.refobjid = dp.objid AND d.refobjsubid = dp.objsubid + ) + SELECT pg_describe_object(classid, objid, objsubid) as obj, + pg_identify_object(classid, objid, objsubid) as ident, + pg_identify_object_as_address(classid, objid, objsubid) as addr + FROM deps +) s +ORDER BY obj COLLATE "C", ident::text COLLATE "C"; + \a\t SELECT pg_get_propgraphdef('g2'::regclass); SELECT pg_get_propgraphdef('g3'::regclass); diff --git a/src/test/regress/sql/event_trigger.sql b/src/test/regress/sql/event_trigger.sql index 32e9bb58c5e..271f443378b 100644 --- a/src/test/regress/sql/event_trigger.sql +++ b/src/test/regress/sql/event_trigger.sql @@ -143,6 +143,19 @@ create user mapping for regress_evt_user server useless_server; alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +CREATE TABLE t2x (i int PRIMARY KEY, j text); + +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); + +DROP PROPERTY GRAPH gx; +DROP TABLE t1x, t2x; + -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; diff --git a/src/test/regress/sql/object_address.sql b/src/test/regress/sql/object_address.sql index 1bbe9457c1c..27109d421c7 100644 --- a/src/test/regress/sql/object_address.sql +++ b/src/test/regress/sql/object_address.sql @@ -67,7 +67,9 @@ DECLARE BEGIN FOR objtype IN VALUES ('toast table'), ('index column'), ('sequence column'), ('toast table column'), ('view column'), ('materialized view column'), - ('property graph element'), ('property graph label'), ('property graph property') + ('property graph element'), ('property graph element label'), + ('property graph label'), ('property graph label property'), + ('property graph property') LOOP BEGIN PERFORM pg_get_object_address(objtype, '{one}', '{}'); @@ -282,7 +284,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace -- 2.34.1 --R84XrR4Hgw0dH3Ec-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v2] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-23 09:27 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-23 09:27 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing them to hit the default case and error out with "unsupported object class". During DROP PROPERTY GRAPH, this manifests when an event trigger is active, because pg_event_trigger_ddl_commands() calls these functions. The same code paths are also reachable via pg_identify_object() and pg_identify_object_as_address(). This commit adds the missing cases. Test coverage is added in object_address.sql for these two catalog types via the zero-OID test that exercises pg_identify_object() and pg_identify_object_as_address(). A test in event_trigger.sql verifies that DROP PROPERTY GRAPH works correctly when an event trigger is active. Author: Bertrand Drouvot <[email protected]> Reviewed-by: Michael Paquier <[email protected]> Reviewed-by: Ashutosh Bapat <[email protected]> Discussion: https://postgr.es/m/aej1DkLwhyZWmtxJ@bdtpg --- src/backend/catalog/objectaddress.c | 93 ++++++++++++++++++++ src/test/regress/expected/event_trigger.out | 17 ++++ src/test/regress/expected/object_address.out | 4 + src/test/regress/sql/event_trigger.sql | 13 +++ src/test/regress/sql/object_address.sql | 2 + 5 files changed, 129 insertions(+) 62.4% src/backend/catalog/ 25.6% src/test/regress/expected/ 11.8% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/event_trigger.out b/src/test/regress/expected/event_trigger.out index 065f586310f..ed8d5df397e 100644 --- a/src/test/regress/expected/event_trigger.out +++ b/src/test/regress/expected/event_trigger.out @@ -173,6 +173,23 @@ NOTICE: test_event_trigger: ddl_command_end CREATE USER MAPPING alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; NOTICE: test_event_trigger: ddl_command_end ALTER DEFAULT PRIVILEGES +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE TABLE t2x (i int PRIMARY KEY, j text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); +NOTICE: test_event_trigger: ddl_command_end CREATE PROPERTY GRAPH +DROP PROPERTY GRAPH gx; +NOTICE: test_event_trigger: ddl_command_end DROP PROPERTY GRAPH +DROP TABLE t1x, t2x; +NOTICE: test_event_trigger: ddl_command_end DROP TABLE -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; ERROR: permission denied to change owner of event trigger "regress_event_trigger" diff --git a/src/test/regress/expected/object_address.out b/src/test/regress/expected/object_address.out index 97227d67a54..729c3537f25 100644 --- a/src/test/regress/expected/object_address.out +++ b/src/test/regress/expected/object_address.out @@ -593,7 +593,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace @@ -653,6 +655,8 @@ ORDER BY objects.classid, objects.objid, objects.objsubid; ("(""parameter ACL"",,,)")|("(""parameter ACL"",,)")|NULL ("(""property graph element"",,,)")|("(""property graph element"",,)")|NULL ("(""property graph label"",,,)")|("(""property graph label"",,)")|NULL +("(""property graph element label"",,,)")|("(""property graph element label"",,)")|NULL ("(""property graph property"",,,)")|("(""property graph property"",,)")|NULL +("(""property graph label property"",,,)")|("(""property graph label property"",,)")|NULL -- restore normal output mode \a\t diff --git a/src/test/regress/sql/event_trigger.sql b/src/test/regress/sql/event_trigger.sql index 32e9bb58c5e..271f443378b 100644 --- a/src/test/regress/sql/event_trigger.sql +++ b/src/test/regress/sql/event_trigger.sql @@ -143,6 +143,19 @@ create user mapping for regress_evt_user server useless_server; alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +CREATE TABLE t2x (i int PRIMARY KEY, j text); + +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); + +DROP PROPERTY GRAPH gx; +DROP TABLE t1x, t2x; + -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; diff --git a/src/test/regress/sql/object_address.sql b/src/test/regress/sql/object_address.sql index 1bbe9457c1c..620dacf1045 100644 --- a/src/test/regress/sql/object_address.sql +++ b/src/test/regress/sql/object_address.sql @@ -282,7 +282,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace -- 2.34.1 --gtUR827Uq8d5gVsQ-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v2] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-23 09:27 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-23 09:27 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing them to hit the default case and error out with "unsupported object class". During DROP PROPERTY GRAPH, this manifests when an event trigger is active, because pg_event_trigger_ddl_commands() calls these functions. The same code paths are also reachable via pg_identify_object() and pg_identify_object_as_address(). This commit adds the missing cases. Test coverage is added in object_address.sql for these two catalog types via the zero-OID test that exercises pg_identify_object() and pg_identify_object_as_address(). A test in event_trigger.sql verifies that DROP PROPERTY GRAPH works correctly when an event trigger is active. Author: Bertrand Drouvot <[email protected]> Reviewed-by: Michael Paquier <[email protected]> Reviewed-by: Ashutosh Bapat <[email protected]> Discussion: https://postgr.es/m/aej1DkLwhyZWmtxJ@bdtpg --- src/backend/catalog/objectaddress.c | 93 ++++++++++++++++++++ src/test/regress/expected/event_trigger.out | 17 ++++ src/test/regress/expected/object_address.out | 4 + src/test/regress/sql/event_trigger.sql | 13 +++ src/test/regress/sql/object_address.sql | 2 + 5 files changed, 129 insertions(+) 62.4% src/backend/catalog/ 25.6% src/test/regress/expected/ 11.8% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/event_trigger.out b/src/test/regress/expected/event_trigger.out index 065f586310f..ed8d5df397e 100644 --- a/src/test/regress/expected/event_trigger.out +++ b/src/test/regress/expected/event_trigger.out @@ -173,6 +173,23 @@ NOTICE: test_event_trigger: ddl_command_end CREATE USER MAPPING alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; NOTICE: test_event_trigger: ddl_command_end ALTER DEFAULT PRIVILEGES +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE TABLE t2x (i int PRIMARY KEY, j text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); +NOTICE: test_event_trigger: ddl_command_end CREATE PROPERTY GRAPH +DROP PROPERTY GRAPH gx; +NOTICE: test_event_trigger: ddl_command_end DROP PROPERTY GRAPH +DROP TABLE t1x, t2x; +NOTICE: test_event_trigger: ddl_command_end DROP TABLE -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; ERROR: permission denied to change owner of event trigger "regress_event_trigger" diff --git a/src/test/regress/expected/object_address.out b/src/test/regress/expected/object_address.out index 97227d67a54..729c3537f25 100644 --- a/src/test/regress/expected/object_address.out +++ b/src/test/regress/expected/object_address.out @@ -593,7 +593,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace @@ -653,6 +655,8 @@ ORDER BY objects.classid, objects.objid, objects.objsubid; ("(""parameter ACL"",,,)")|("(""parameter ACL"",,)")|NULL ("(""property graph element"",,,)")|("(""property graph element"",,)")|NULL ("(""property graph label"",,,)")|("(""property graph label"",,)")|NULL +("(""property graph element label"",,,)")|("(""property graph element label"",,)")|NULL ("(""property graph property"",,,)")|("(""property graph property"",,)")|NULL +("(""property graph label property"",,,)")|("(""property graph label property"",,)")|NULL -- restore normal output mode \a\t diff --git a/src/test/regress/sql/event_trigger.sql b/src/test/regress/sql/event_trigger.sql index 32e9bb58c5e..271f443378b 100644 --- a/src/test/regress/sql/event_trigger.sql +++ b/src/test/regress/sql/event_trigger.sql @@ -143,6 +143,19 @@ create user mapping for regress_evt_user server useless_server; alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +CREATE TABLE t2x (i int PRIMARY KEY, j text); + +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); + +DROP PROPERTY GRAPH gx; +DROP TABLE t1x, t2x; + -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; diff --git a/src/test/regress/sql/object_address.sql b/src/test/regress/sql/object_address.sql index 1bbe9457c1c..620dacf1045 100644 --- a/src/test/regress/sql/object_address.sql +++ b/src/test/regress/sql/object_address.sql @@ -282,7 +282,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace -- 2.34.1 --gtUR827Uq8d5gVsQ-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v2] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-23 09:27 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-23 09:27 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing them to hit the default case and error out with "unsupported object class". During DROP PROPERTY GRAPH, this manifests when an event trigger is active, because pg_event_trigger_ddl_commands() calls these functions. The same code paths are also reachable via pg_identify_object() and pg_identify_object_as_address(). This commit adds the missing cases. Test coverage is added in object_address.sql for these two catalog types via the zero-OID test that exercises pg_identify_object() and pg_identify_object_as_address(). A test in event_trigger.sql verifies that DROP PROPERTY GRAPH works correctly when an event trigger is active. Author: Bertrand Drouvot <[email protected]> Reviewed-by: Michael Paquier <[email protected]> Reviewed-by: Ashutosh Bapat <[email protected]> Discussion: https://postgr.es/m/aej1DkLwhyZWmtxJ@bdtpg --- src/backend/catalog/objectaddress.c | 93 ++++++++++++++++++++ src/test/regress/expected/event_trigger.out | 17 ++++ src/test/regress/expected/object_address.out | 4 + src/test/regress/sql/event_trigger.sql | 13 +++ src/test/regress/sql/object_address.sql | 2 + 5 files changed, 129 insertions(+) 62.4% src/backend/catalog/ 25.6% src/test/regress/expected/ 11.8% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/event_trigger.out b/src/test/regress/expected/event_trigger.out index 065f586310f..ed8d5df397e 100644 --- a/src/test/regress/expected/event_trigger.out +++ b/src/test/regress/expected/event_trigger.out @@ -173,6 +173,23 @@ NOTICE: test_event_trigger: ddl_command_end CREATE USER MAPPING alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; NOTICE: test_event_trigger: ddl_command_end ALTER DEFAULT PRIVILEGES +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE TABLE t2x (i int PRIMARY KEY, j text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); +NOTICE: test_event_trigger: ddl_command_end CREATE PROPERTY GRAPH +DROP PROPERTY GRAPH gx; +NOTICE: test_event_trigger: ddl_command_end DROP PROPERTY GRAPH +DROP TABLE t1x, t2x; +NOTICE: test_event_trigger: ddl_command_end DROP TABLE -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; ERROR: permission denied to change owner of event trigger "regress_event_trigger" diff --git a/src/test/regress/expected/object_address.out b/src/test/regress/expected/object_address.out index 97227d67a54..729c3537f25 100644 --- a/src/test/regress/expected/object_address.out +++ b/src/test/regress/expected/object_address.out @@ -593,7 +593,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace @@ -653,6 +655,8 @@ ORDER BY objects.classid, objects.objid, objects.objsubid; ("(""parameter ACL"",,,)")|("(""parameter ACL"",,)")|NULL ("(""property graph element"",,,)")|("(""property graph element"",,)")|NULL ("(""property graph label"",,,)")|("(""property graph label"",,)")|NULL +("(""property graph element label"",,,)")|("(""property graph element label"",,)")|NULL ("(""property graph property"",,,)")|("(""property graph property"",,)")|NULL +("(""property graph label property"",,,)")|("(""property graph label property"",,)")|NULL -- restore normal output mode \a\t diff --git a/src/test/regress/sql/event_trigger.sql b/src/test/regress/sql/event_trigger.sql index 32e9bb58c5e..271f443378b 100644 --- a/src/test/regress/sql/event_trigger.sql +++ b/src/test/regress/sql/event_trigger.sql @@ -143,6 +143,19 @@ create user mapping for regress_evt_user server useless_server; alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +CREATE TABLE t2x (i int PRIMARY KEY, j text); + +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); + +DROP PROPERTY GRAPH gx; +DROP TABLE t1x, t2x; + -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; diff --git a/src/test/regress/sql/object_address.sql b/src/test/regress/sql/object_address.sql index 1bbe9457c1c..620dacf1045 100644 --- a/src/test/regress/sql/object_address.sql +++ b/src/test/regress/sql/object_address.sql @@ -282,7 +282,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace -- 2.34.1 --gtUR827Uq8d5gVsQ-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v3] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-23 09:27 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-23 09:27 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing them to hit the default case and error out with "unsupported object class". During DROP PROPERTY GRAPH, this manifests when an event trigger is active, because pg_event_trigger_ddl_commands() calls these functions. The same code paths are also reachable via pg_identify_object() and pg_identify_object_as_address(). This commit adds the missing cases. Test coverage is added in object_address.sql for these two catalog types and in create_property_graph.sql covering all property graph object types. A test in event_trigger.sql verifies that DROP PROPERTY GRAPH works correctly when an event trigger is active. Author: Bertrand Drouvot <[email protected]> Reviewed-by: Michael Paquier <[email protected]> Reviewed-by: Ashutosh Bapat <[email protected]> Discussion: https://postgr.es/m/aej1DkLwhyZWmtxJ@bdtpg --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 78 ++++++++++++++++ src/test/regress/expected/event_trigger.out | 17 ++++ src/test/regress/expected/object_address.out | 10 +- .../regress/sql/create_property_graph.sql | 23 +++++ src/test/regress/sql/event_trigger.sql | 13 +++ src/test/regress/sql/object_address.sql | 6 +- 7 files changed, 238 insertions(+), 2 deletions(-) 14.7% src/backend/catalog/ 75.5% src/test/regress/expected/ 9.7% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..eb9e17fb727 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -752,6 +752,84 @@ SELECT (pg_identify_object(classid, objid, objsubid)).* type | create_property_graph_tests | g2 | create_property_graph_tests.g2 (21 rows) +-- test object address functions with recursive dependency walk +-- covers all property graph object types including indirect dependents +SELECT * +FROM ( + WITH RECURSIVE deps (classid, objid, objsubid, refclassid, refobjid, refobjsubid) AS ( + SELECT classid, objid, objsubid, + refclassid, refobjid, refobjsubid + FROM pg_depend + WHERE refclassid = 'pg_class'::regclass AND + refobjid = 'create_property_graph_tests.gt'::regclass + UNION ALL + SELECT d.classid, d.objid, d.objsubid, + d.refclassid, d.refobjid, d.refobjsubid + FROM pg_depend d + JOIN deps dp ON d.refclassid = dp.classid AND d.refobjid = dp.objid AND d.refobjsubid = dp.objsubid + ) + SELECT pg_describe_object(classid, objid, objsubid) as obj, + pg_identify_object(classid, objid, objsubid) as ident, + pg_identify_object_as_address(classid, objid, objsubid) as addr + FROM deps +) s +ORDER BY obj COLLATE "C", ident::text COLLATE "C"; + obj | ident | addr +----------------------------------------------------------+----------------------------------------------------------------------------+---------------------------------------------------------------------------- + edge e of property graph gt | ("property graph element",,,"e of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,e}",{}) + edge e of property graph gt | ("property graph element",,,"e of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,e}",{}) + edge e of property graph gt | ("property graph element",,,"e of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of property graph gt | ("property graph label",,,"e of create_property_graph_tests.gt") | ("property graph label","{create_property_graph_tests,gt,e}",{}) + label v1 of property graph gt | ("property graph label",,,"v1 of create_property_graph_tests.gt") | ("property graph label","{create_property_graph_tests,gt,v1}",{}) + label v1 of vertex v1 of property graph gt | ("property graph element label",,,"v1 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v1}",{}) + label v1 of vertex v1 of property graph gt | ("property graph element label",,,"v1 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v1}",{}) + label v2 of property graph gt | ("property graph label",,,"v2 of create_property_graph_tests.gt") | ("property graph label","{create_property_graph_tests,gt,v2}",{}) + label v2 of vertex v2 of property graph gt | ("property graph element label",,,"v2 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v2}",{}) + label v2 of vertex v2 of property graph gt | ("property graph element label",,,"v2 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v2}",{}) + property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property a of property graph gt | ("property graph property",,,"a of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,a}",{}) + property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property b of property graph gt | ("property graph property",,,"b of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,b}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of property graph gt | ("property graph property",,,"c of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,c}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of property graph gt | ("property graph property",,,"k1 of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,k1}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of property graph gt | ("property graph property",,,"k2 of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,k2}",{}) + property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property m of property graph gt | ("property graph property",,,"m of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,m}",{}) + property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property n of property graph gt | ("property graph property",,,"n of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,n}",{}) + type gt | (type,create_property_graph_tests,gt,create_property_graph_tests.gt) | (type,{create_property_graph_tests.gt},{}) + type gt[] | (type,create_property_graph_tests,_gt,create_property_graph_tests.gt[]) | (type,{create_property_graph_tests.gt[]},{}) + vertex v1 of property graph gt | ("property graph element",,,"v1 of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,v1}",{}) + vertex v2 of property graph gt | ("property graph element",,,"v2 of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,v2}",{}) +(52 rows) + \a\t SELECT pg_get_propgraphdef('g2'::regclass); CREATE PROPERTY GRAPH create_property_graph_tests.g2 diff --git a/src/test/regress/expected/event_trigger.out b/src/test/regress/expected/event_trigger.out index 065f586310f..ed8d5df397e 100644 --- a/src/test/regress/expected/event_trigger.out +++ b/src/test/regress/expected/event_trigger.out @@ -173,6 +173,23 @@ NOTICE: test_event_trigger: ddl_command_end CREATE USER MAPPING alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; NOTICE: test_event_trigger: ddl_command_end ALTER DEFAULT PRIVILEGES +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE TABLE t2x (i int PRIMARY KEY, j text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); +NOTICE: test_event_trigger: ddl_command_end CREATE PROPERTY GRAPH +DROP PROPERTY GRAPH gx; +NOTICE: test_event_trigger: ddl_command_end DROP PROPERTY GRAPH +DROP TABLE t1x, t2x; +NOTICE: test_event_trigger: ddl_command_end DROP TABLE -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; ERROR: permission denied to change owner of event trigger "regress_event_trigger" diff --git a/src/test/regress/expected/object_address.out b/src/test/regress/expected/object_address.out index 97227d67a54..5e53f0b092e 100644 --- a/src/test/regress/expected/object_address.out +++ b/src/test/regress/expected/object_address.out @@ -67,7 +67,9 @@ DECLARE BEGIN FOR objtype IN VALUES ('toast table'), ('index column'), ('sequence column'), ('toast table column'), ('view column'), ('materialized view column'), - ('property graph element'), ('property graph label'), ('property graph property') + ('property graph element'), ('property graph element label'), + ('property graph label'), ('property graph label property'), + ('property graph property') LOOP BEGIN PERFORM pg_get_object_address(objtype, '{one}', '{}'); @@ -84,7 +86,9 @@ WARNING: error for toast table column: unsupported object type "toast table col WARNING: error for view column: unsupported object type "view column" WARNING: error for materialized view column: unsupported object type "materialized view column" WARNING: error for property graph element: unsupported object type "property graph element" +WARNING: error for property graph element label: unrecognized object type "property graph element label" WARNING: error for property graph label: unsupported object type "property graph label" +WARNING: error for property graph label property: unrecognized object type "property graph label property" WARNING: error for property graph property: unsupported object type "property graph property" -- miscellaneous other errors select * from pg_get_object_address('operator of access method', '{btree,integer_ops,1}', '{int4,bool}'); @@ -593,7 +597,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace @@ -653,6 +659,8 @@ ORDER BY objects.classid, objects.objid, objects.objsubid; ("(""parameter ACL"",,,)")|("(""parameter ACL"",,)")|NULL ("(""property graph element"",,,)")|("(""property graph element"",,)")|NULL ("(""property graph label"",,,)")|("(""property graph label"",,)")|NULL +("(""property graph element label"",,,)")|("(""property graph element label"",,)")|NULL ("(""property graph property"",,,)")|("(""property graph property"",,)")|NULL +("(""property graph label property"",,,)")|("(""property graph label property"",,)")|NULL -- restore normal output mode \a\t diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..9608dd5c4af 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -298,6 +298,29 @@ SELECT (pg_identify_object(classid, objid, objsubid)).* refobjid = 'create_property_graph_tests.g2'::regclass ORDER BY 1, 2, 3, 4; +-- test object address functions with recursive dependency walk +-- covers all property graph object types including indirect dependents +SELECT * +FROM ( + WITH RECURSIVE deps (classid, objid, objsubid, refclassid, refobjid, refobjsubid) AS ( + SELECT classid, objid, objsubid, + refclassid, refobjid, refobjsubid + FROM pg_depend + WHERE refclassid = 'pg_class'::regclass AND + refobjid = 'create_property_graph_tests.gt'::regclass + UNION ALL + SELECT d.classid, d.objid, d.objsubid, + d.refclassid, d.refobjid, d.refobjsubid + FROM pg_depend d + JOIN deps dp ON d.refclassid = dp.classid AND d.refobjid = dp.objid AND d.refobjsubid = dp.objsubid + ) + SELECT pg_describe_object(classid, objid, objsubid) as obj, + pg_identify_object(classid, objid, objsubid) as ident, + pg_identify_object_as_address(classid, objid, objsubid) as addr + FROM deps +) s +ORDER BY obj COLLATE "C", ident::text COLLATE "C"; + \a\t SELECT pg_get_propgraphdef('g2'::regclass); SELECT pg_get_propgraphdef('g3'::regclass); diff --git a/src/test/regress/sql/event_trigger.sql b/src/test/regress/sql/event_trigger.sql index 32e9bb58c5e..271f443378b 100644 --- a/src/test/regress/sql/event_trigger.sql +++ b/src/test/regress/sql/event_trigger.sql @@ -143,6 +143,19 @@ create user mapping for regress_evt_user server useless_server; alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +CREATE TABLE t2x (i int PRIMARY KEY, j text); + +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); + +DROP PROPERTY GRAPH gx; +DROP TABLE t1x, t2x; + -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; diff --git a/src/test/regress/sql/object_address.sql b/src/test/regress/sql/object_address.sql index 1bbe9457c1c..27109d421c7 100644 --- a/src/test/regress/sql/object_address.sql +++ b/src/test/regress/sql/object_address.sql @@ -67,7 +67,9 @@ DECLARE BEGIN FOR objtype IN VALUES ('toast table'), ('index column'), ('sequence column'), ('toast table column'), ('view column'), ('materialized view column'), - ('property graph element'), ('property graph label'), ('property graph property') + ('property graph element'), ('property graph element label'), + ('property graph label'), ('property graph label property'), + ('property graph property') LOOP BEGIN PERFORM pg_get_object_address(objtype, '{one}', '{}'); @@ -282,7 +284,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace -- 2.34.1 --R84XrR4Hgw0dH3Ec-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v2] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-23 09:27 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-23 09:27 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing them to hit the default case and error out with "unsupported object class". During DROP PROPERTY GRAPH, this manifests when an event trigger is active, because pg_event_trigger_ddl_commands() calls these functions. The same code paths are also reachable via pg_identify_object() and pg_identify_object_as_address(). This commit adds the missing cases. Test coverage is added in object_address.sql for these two catalog types via the zero-OID test that exercises pg_identify_object() and pg_identify_object_as_address(). A test in event_trigger.sql verifies that DROP PROPERTY GRAPH works correctly when an event trigger is active. Author: Bertrand Drouvot <[email protected]> Reviewed-by: Michael Paquier <[email protected]> Reviewed-by: Ashutosh Bapat <[email protected]> Discussion: https://postgr.es/m/aej1DkLwhyZWmtxJ@bdtpg --- src/backend/catalog/objectaddress.c | 93 ++++++++++++++++++++ src/test/regress/expected/event_trigger.out | 17 ++++ src/test/regress/expected/object_address.out | 4 + src/test/regress/sql/event_trigger.sql | 13 +++ src/test/regress/sql/object_address.sql | 2 + 5 files changed, 129 insertions(+) 62.4% src/backend/catalog/ 25.6% src/test/regress/expected/ 11.8% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/event_trigger.out b/src/test/regress/expected/event_trigger.out index 065f586310f..ed8d5df397e 100644 --- a/src/test/regress/expected/event_trigger.out +++ b/src/test/regress/expected/event_trigger.out @@ -173,6 +173,23 @@ NOTICE: test_event_trigger: ddl_command_end CREATE USER MAPPING alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; NOTICE: test_event_trigger: ddl_command_end ALTER DEFAULT PRIVILEGES +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE TABLE t2x (i int PRIMARY KEY, j text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); +NOTICE: test_event_trigger: ddl_command_end CREATE PROPERTY GRAPH +DROP PROPERTY GRAPH gx; +NOTICE: test_event_trigger: ddl_command_end DROP PROPERTY GRAPH +DROP TABLE t1x, t2x; +NOTICE: test_event_trigger: ddl_command_end DROP TABLE -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; ERROR: permission denied to change owner of event trigger "regress_event_trigger" diff --git a/src/test/regress/expected/object_address.out b/src/test/regress/expected/object_address.out index 97227d67a54..729c3537f25 100644 --- a/src/test/regress/expected/object_address.out +++ b/src/test/regress/expected/object_address.out @@ -593,7 +593,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace @@ -653,6 +655,8 @@ ORDER BY objects.classid, objects.objid, objects.objsubid; ("(""parameter ACL"",,,)")|("(""parameter ACL"",,)")|NULL ("(""property graph element"",,,)")|("(""property graph element"",,)")|NULL ("(""property graph label"",,,)")|("(""property graph label"",,)")|NULL +("(""property graph element label"",,,)")|("(""property graph element label"",,)")|NULL ("(""property graph property"",,,)")|("(""property graph property"",,)")|NULL +("(""property graph label property"",,,)")|("(""property graph label property"",,)")|NULL -- restore normal output mode \a\t diff --git a/src/test/regress/sql/event_trigger.sql b/src/test/regress/sql/event_trigger.sql index 32e9bb58c5e..271f443378b 100644 --- a/src/test/regress/sql/event_trigger.sql +++ b/src/test/regress/sql/event_trigger.sql @@ -143,6 +143,19 @@ create user mapping for regress_evt_user server useless_server; alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +CREATE TABLE t2x (i int PRIMARY KEY, j text); + +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); + +DROP PROPERTY GRAPH gx; +DROP TABLE t1x, t2x; + -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; diff --git a/src/test/regress/sql/object_address.sql b/src/test/regress/sql/object_address.sql index 1bbe9457c1c..620dacf1045 100644 --- a/src/test/regress/sql/object_address.sql +++ b/src/test/regress/sql/object_address.sql @@ -282,7 +282,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace -- 2.34.1 --gtUR827Uq8d5gVsQ-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v3] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-23 09:27 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-23 09:27 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing them to hit the default case and error out with "unsupported object class". During DROP PROPERTY GRAPH, this manifests when an event trigger is active, because pg_event_trigger_ddl_commands() calls these functions. The same code paths are also reachable via pg_identify_object() and pg_identify_object_as_address(). This commit adds the missing cases. Test coverage is added in object_address.sql for these two catalog types and in create_property_graph.sql covering all property graph object types. A test in event_trigger.sql verifies that DROP PROPERTY GRAPH works correctly when an event trigger is active. Author: Bertrand Drouvot <[email protected]> Reviewed-by: Michael Paquier <[email protected]> Reviewed-by: Ashutosh Bapat <[email protected]> Discussion: https://postgr.es/m/aej1DkLwhyZWmtxJ@bdtpg --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 78 ++++++++++++++++ src/test/regress/expected/event_trigger.out | 17 ++++ src/test/regress/expected/object_address.out | 10 +- .../regress/sql/create_property_graph.sql | 23 +++++ src/test/regress/sql/event_trigger.sql | 13 +++ src/test/regress/sql/object_address.sql | 6 +- 7 files changed, 238 insertions(+), 2 deletions(-) 14.7% src/backend/catalog/ 75.5% src/test/regress/expected/ 9.7% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..eb9e17fb727 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -752,6 +752,84 @@ SELECT (pg_identify_object(classid, objid, objsubid)).* type | create_property_graph_tests | g2 | create_property_graph_tests.g2 (21 rows) +-- test object address functions with recursive dependency walk +-- covers all property graph object types including indirect dependents +SELECT * +FROM ( + WITH RECURSIVE deps (classid, objid, objsubid, refclassid, refobjid, refobjsubid) AS ( + SELECT classid, objid, objsubid, + refclassid, refobjid, refobjsubid + FROM pg_depend + WHERE refclassid = 'pg_class'::regclass AND + refobjid = 'create_property_graph_tests.gt'::regclass + UNION ALL + SELECT d.classid, d.objid, d.objsubid, + d.refclassid, d.refobjid, d.refobjsubid + FROM pg_depend d + JOIN deps dp ON d.refclassid = dp.classid AND d.refobjid = dp.objid AND d.refobjsubid = dp.objsubid + ) + SELECT pg_describe_object(classid, objid, objsubid) as obj, + pg_identify_object(classid, objid, objsubid) as ident, + pg_identify_object_as_address(classid, objid, objsubid) as addr + FROM deps +) s +ORDER BY obj COLLATE "C", ident::text COLLATE "C"; + obj | ident | addr +----------------------------------------------------------+----------------------------------------------------------------------------+---------------------------------------------------------------------------- + edge e of property graph gt | ("property graph element",,,"e of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,e}",{}) + edge e of property graph gt | ("property graph element",,,"e of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,e}",{}) + edge e of property graph gt | ("property graph element",,,"e of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of property graph gt | ("property graph label",,,"e of create_property_graph_tests.gt") | ("property graph label","{create_property_graph_tests,gt,e}",{}) + label v1 of property graph gt | ("property graph label",,,"v1 of create_property_graph_tests.gt") | ("property graph label","{create_property_graph_tests,gt,v1}",{}) + label v1 of vertex v1 of property graph gt | ("property graph element label",,,"v1 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v1}",{}) + label v1 of vertex v1 of property graph gt | ("property graph element label",,,"v1 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v1}",{}) + label v2 of property graph gt | ("property graph label",,,"v2 of create_property_graph_tests.gt") | ("property graph label","{create_property_graph_tests,gt,v2}",{}) + label v2 of vertex v2 of property graph gt | ("property graph element label",,,"v2 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v2}",{}) + label v2 of vertex v2 of property graph gt | ("property graph element label",,,"v2 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v2}",{}) + property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property a of property graph gt | ("property graph property",,,"a of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,a}",{}) + property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property b of property graph gt | ("property graph property",,,"b of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,b}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of property graph gt | ("property graph property",,,"c of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,c}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of property graph gt | ("property graph property",,,"k1 of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,k1}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of property graph gt | ("property graph property",,,"k2 of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,k2}",{}) + property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property m of property graph gt | ("property graph property",,,"m of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,m}",{}) + property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property n of property graph gt | ("property graph property",,,"n of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,n}",{}) + type gt | (type,create_property_graph_tests,gt,create_property_graph_tests.gt) | (type,{create_property_graph_tests.gt},{}) + type gt[] | (type,create_property_graph_tests,_gt,create_property_graph_tests.gt[]) | (type,{create_property_graph_tests.gt[]},{}) + vertex v1 of property graph gt | ("property graph element",,,"v1 of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,v1}",{}) + vertex v2 of property graph gt | ("property graph element",,,"v2 of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,v2}",{}) +(52 rows) + \a\t SELECT pg_get_propgraphdef('g2'::regclass); CREATE PROPERTY GRAPH create_property_graph_tests.g2 diff --git a/src/test/regress/expected/event_trigger.out b/src/test/regress/expected/event_trigger.out index 065f586310f..ed8d5df397e 100644 --- a/src/test/regress/expected/event_trigger.out +++ b/src/test/regress/expected/event_trigger.out @@ -173,6 +173,23 @@ NOTICE: test_event_trigger: ddl_command_end CREATE USER MAPPING alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; NOTICE: test_event_trigger: ddl_command_end ALTER DEFAULT PRIVILEGES +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE TABLE t2x (i int PRIMARY KEY, j text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); +NOTICE: test_event_trigger: ddl_command_end CREATE PROPERTY GRAPH +DROP PROPERTY GRAPH gx; +NOTICE: test_event_trigger: ddl_command_end DROP PROPERTY GRAPH +DROP TABLE t1x, t2x; +NOTICE: test_event_trigger: ddl_command_end DROP TABLE -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; ERROR: permission denied to change owner of event trigger "regress_event_trigger" diff --git a/src/test/regress/expected/object_address.out b/src/test/regress/expected/object_address.out index 97227d67a54..5e53f0b092e 100644 --- a/src/test/regress/expected/object_address.out +++ b/src/test/regress/expected/object_address.out @@ -67,7 +67,9 @@ DECLARE BEGIN FOR objtype IN VALUES ('toast table'), ('index column'), ('sequence column'), ('toast table column'), ('view column'), ('materialized view column'), - ('property graph element'), ('property graph label'), ('property graph property') + ('property graph element'), ('property graph element label'), + ('property graph label'), ('property graph label property'), + ('property graph property') LOOP BEGIN PERFORM pg_get_object_address(objtype, '{one}', '{}'); @@ -84,7 +86,9 @@ WARNING: error for toast table column: unsupported object type "toast table col WARNING: error for view column: unsupported object type "view column" WARNING: error for materialized view column: unsupported object type "materialized view column" WARNING: error for property graph element: unsupported object type "property graph element" +WARNING: error for property graph element label: unrecognized object type "property graph element label" WARNING: error for property graph label: unsupported object type "property graph label" +WARNING: error for property graph label property: unrecognized object type "property graph label property" WARNING: error for property graph property: unsupported object type "property graph property" -- miscellaneous other errors select * from pg_get_object_address('operator of access method', '{btree,integer_ops,1}', '{int4,bool}'); @@ -593,7 +597,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace @@ -653,6 +659,8 @@ ORDER BY objects.classid, objects.objid, objects.objsubid; ("(""parameter ACL"",,,)")|("(""parameter ACL"",,)")|NULL ("(""property graph element"",,,)")|("(""property graph element"",,)")|NULL ("(""property graph label"",,,)")|("(""property graph label"",,)")|NULL +("(""property graph element label"",,,)")|("(""property graph element label"",,)")|NULL ("(""property graph property"",,,)")|("(""property graph property"",,)")|NULL +("(""property graph label property"",,,)")|("(""property graph label property"",,)")|NULL -- restore normal output mode \a\t diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..9608dd5c4af 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -298,6 +298,29 @@ SELECT (pg_identify_object(classid, objid, objsubid)).* refobjid = 'create_property_graph_tests.g2'::regclass ORDER BY 1, 2, 3, 4; +-- test object address functions with recursive dependency walk +-- covers all property graph object types including indirect dependents +SELECT * +FROM ( + WITH RECURSIVE deps (classid, objid, objsubid, refclassid, refobjid, refobjsubid) AS ( + SELECT classid, objid, objsubid, + refclassid, refobjid, refobjsubid + FROM pg_depend + WHERE refclassid = 'pg_class'::regclass AND + refobjid = 'create_property_graph_tests.gt'::regclass + UNION ALL + SELECT d.classid, d.objid, d.objsubid, + d.refclassid, d.refobjid, d.refobjsubid + FROM pg_depend d + JOIN deps dp ON d.refclassid = dp.classid AND d.refobjid = dp.objid AND d.refobjsubid = dp.objsubid + ) + SELECT pg_describe_object(classid, objid, objsubid) as obj, + pg_identify_object(classid, objid, objsubid) as ident, + pg_identify_object_as_address(classid, objid, objsubid) as addr + FROM deps +) s +ORDER BY obj COLLATE "C", ident::text COLLATE "C"; + \a\t SELECT pg_get_propgraphdef('g2'::regclass); SELECT pg_get_propgraphdef('g3'::regclass); diff --git a/src/test/regress/sql/event_trigger.sql b/src/test/regress/sql/event_trigger.sql index 32e9bb58c5e..271f443378b 100644 --- a/src/test/regress/sql/event_trigger.sql +++ b/src/test/regress/sql/event_trigger.sql @@ -143,6 +143,19 @@ create user mapping for regress_evt_user server useless_server; alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +CREATE TABLE t2x (i int PRIMARY KEY, j text); + +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); + +DROP PROPERTY GRAPH gx; +DROP TABLE t1x, t2x; + -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; diff --git a/src/test/regress/sql/object_address.sql b/src/test/regress/sql/object_address.sql index 1bbe9457c1c..27109d421c7 100644 --- a/src/test/regress/sql/object_address.sql +++ b/src/test/regress/sql/object_address.sql @@ -67,7 +67,9 @@ DECLARE BEGIN FOR objtype IN VALUES ('toast table'), ('index column'), ('sequence column'), ('toast table column'), ('view column'), ('materialized view column'), - ('property graph element'), ('property graph label'), ('property graph property') + ('property graph element'), ('property graph element label'), + ('property graph label'), ('property graph label property'), + ('property graph property') LOOP BEGIN PERFORM pg_get_object_address(objtype, '{one}', '{}'); @@ -282,7 +284,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace -- 2.34.1 --R84XrR4Hgw0dH3Ec-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v2] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-23 09:27 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-23 09:27 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing them to hit the default case and error out with "unsupported object class". During DROP PROPERTY GRAPH, this manifests when an event trigger is active, because pg_event_trigger_ddl_commands() calls these functions. The same code paths are also reachable via pg_identify_object() and pg_identify_object_as_address(). This commit adds the missing cases. Test coverage is added in object_address.sql for these two catalog types via the zero-OID test that exercises pg_identify_object() and pg_identify_object_as_address(). A test in event_trigger.sql verifies that DROP PROPERTY GRAPH works correctly when an event trigger is active. Author: Bertrand Drouvot <[email protected]> Reviewed-by: Michael Paquier <[email protected]> Reviewed-by: Ashutosh Bapat <[email protected]> Discussion: https://postgr.es/m/aej1DkLwhyZWmtxJ@bdtpg --- src/backend/catalog/objectaddress.c | 93 ++++++++++++++++++++ src/test/regress/expected/event_trigger.out | 17 ++++ src/test/regress/expected/object_address.out | 4 + src/test/regress/sql/event_trigger.sql | 13 +++ src/test/regress/sql/object_address.sql | 2 + 5 files changed, 129 insertions(+) 62.4% src/backend/catalog/ 25.6% src/test/regress/expected/ 11.8% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/event_trigger.out b/src/test/regress/expected/event_trigger.out index 065f586310f..ed8d5df397e 100644 --- a/src/test/regress/expected/event_trigger.out +++ b/src/test/regress/expected/event_trigger.out @@ -173,6 +173,23 @@ NOTICE: test_event_trigger: ddl_command_end CREATE USER MAPPING alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; NOTICE: test_event_trigger: ddl_command_end ALTER DEFAULT PRIVILEGES +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE TABLE t2x (i int PRIMARY KEY, j text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); +NOTICE: test_event_trigger: ddl_command_end CREATE PROPERTY GRAPH +DROP PROPERTY GRAPH gx; +NOTICE: test_event_trigger: ddl_command_end DROP PROPERTY GRAPH +DROP TABLE t1x, t2x; +NOTICE: test_event_trigger: ddl_command_end DROP TABLE -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; ERROR: permission denied to change owner of event trigger "regress_event_trigger" diff --git a/src/test/regress/expected/object_address.out b/src/test/regress/expected/object_address.out index 97227d67a54..729c3537f25 100644 --- a/src/test/regress/expected/object_address.out +++ b/src/test/regress/expected/object_address.out @@ -593,7 +593,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace @@ -653,6 +655,8 @@ ORDER BY objects.classid, objects.objid, objects.objsubid; ("(""parameter ACL"",,,)")|("(""parameter ACL"",,)")|NULL ("(""property graph element"",,,)")|("(""property graph element"",,)")|NULL ("(""property graph label"",,,)")|("(""property graph label"",,)")|NULL +("(""property graph element label"",,,)")|("(""property graph element label"",,)")|NULL ("(""property graph property"",,,)")|("(""property graph property"",,)")|NULL +("(""property graph label property"",,,)")|("(""property graph label property"",,)")|NULL -- restore normal output mode \a\t diff --git a/src/test/regress/sql/event_trigger.sql b/src/test/regress/sql/event_trigger.sql index 32e9bb58c5e..271f443378b 100644 --- a/src/test/regress/sql/event_trigger.sql +++ b/src/test/regress/sql/event_trigger.sql @@ -143,6 +143,19 @@ create user mapping for regress_evt_user server useless_server; alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +CREATE TABLE t2x (i int PRIMARY KEY, j text); + +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); + +DROP PROPERTY GRAPH gx; +DROP TABLE t1x, t2x; + -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; diff --git a/src/test/regress/sql/object_address.sql b/src/test/regress/sql/object_address.sql index 1bbe9457c1c..620dacf1045 100644 --- a/src/test/regress/sql/object_address.sql +++ b/src/test/regress/sql/object_address.sql @@ -282,7 +282,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace -- 2.34.1 --gtUR827Uq8d5gVsQ-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v3] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-23 09:27 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-23 09:27 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing them to hit the default case and error out with "unsupported object class". During DROP PROPERTY GRAPH, this manifests when an event trigger is active, because pg_event_trigger_ddl_commands() calls these functions. The same code paths are also reachable via pg_identify_object() and pg_identify_object_as_address(). This commit adds the missing cases. Test coverage is added in object_address.sql for these two catalog types and in create_property_graph.sql covering all property graph object types. A test in event_trigger.sql verifies that DROP PROPERTY GRAPH works correctly when an event trigger is active. Author: Bertrand Drouvot <[email protected]> Reviewed-by: Michael Paquier <[email protected]> Reviewed-by: Ashutosh Bapat <[email protected]> Discussion: https://postgr.es/m/aej1DkLwhyZWmtxJ@bdtpg --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 78 ++++++++++++++++ src/test/regress/expected/event_trigger.out | 17 ++++ src/test/regress/expected/object_address.out | 10 +- .../regress/sql/create_property_graph.sql | 23 +++++ src/test/regress/sql/event_trigger.sql | 13 +++ src/test/regress/sql/object_address.sql | 6 +- 7 files changed, 238 insertions(+), 2 deletions(-) 14.7% src/backend/catalog/ 75.5% src/test/regress/expected/ 9.7% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..eb9e17fb727 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -752,6 +752,84 @@ SELECT (pg_identify_object(classid, objid, objsubid)).* type | create_property_graph_tests | g2 | create_property_graph_tests.g2 (21 rows) +-- test object address functions with recursive dependency walk +-- covers all property graph object types including indirect dependents +SELECT * +FROM ( + WITH RECURSIVE deps (classid, objid, objsubid, refclassid, refobjid, refobjsubid) AS ( + SELECT classid, objid, objsubid, + refclassid, refobjid, refobjsubid + FROM pg_depend + WHERE refclassid = 'pg_class'::regclass AND + refobjid = 'create_property_graph_tests.gt'::regclass + UNION ALL + SELECT d.classid, d.objid, d.objsubid, + d.refclassid, d.refobjid, d.refobjsubid + FROM pg_depend d + JOIN deps dp ON d.refclassid = dp.classid AND d.refobjid = dp.objid AND d.refobjsubid = dp.objsubid + ) + SELECT pg_describe_object(classid, objid, objsubid) as obj, + pg_identify_object(classid, objid, objsubid) as ident, + pg_identify_object_as_address(classid, objid, objsubid) as addr + FROM deps +) s +ORDER BY obj COLLATE "C", ident::text COLLATE "C"; + obj | ident | addr +----------------------------------------------------------+----------------------------------------------------------------------------+---------------------------------------------------------------------------- + edge e of property graph gt | ("property graph element",,,"e of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,e}",{}) + edge e of property graph gt | ("property graph element",,,"e of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,e}",{}) + edge e of property graph gt | ("property graph element",,,"e of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of property graph gt | ("property graph label",,,"e of create_property_graph_tests.gt") | ("property graph label","{create_property_graph_tests,gt,e}",{}) + label v1 of property graph gt | ("property graph label",,,"v1 of create_property_graph_tests.gt") | ("property graph label","{create_property_graph_tests,gt,v1}",{}) + label v1 of vertex v1 of property graph gt | ("property graph element label",,,"v1 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v1}",{}) + label v1 of vertex v1 of property graph gt | ("property graph element label",,,"v1 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v1}",{}) + label v2 of property graph gt | ("property graph label",,,"v2 of create_property_graph_tests.gt") | ("property graph label","{create_property_graph_tests,gt,v2}",{}) + label v2 of vertex v2 of property graph gt | ("property graph element label",,,"v2 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v2}",{}) + label v2 of vertex v2 of property graph gt | ("property graph element label",,,"v2 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v2}",{}) + property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property a of property graph gt | ("property graph property",,,"a of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,a}",{}) + property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property b of property graph gt | ("property graph property",,,"b of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,b}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of property graph gt | ("property graph property",,,"c of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,c}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of property graph gt | ("property graph property",,,"k1 of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,k1}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of property graph gt | ("property graph property",,,"k2 of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,k2}",{}) + property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property m of property graph gt | ("property graph property",,,"m of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,m}",{}) + property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property n of property graph gt | ("property graph property",,,"n of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,n}",{}) + type gt | (type,create_property_graph_tests,gt,create_property_graph_tests.gt) | (type,{create_property_graph_tests.gt},{}) + type gt[] | (type,create_property_graph_tests,_gt,create_property_graph_tests.gt[]) | (type,{create_property_graph_tests.gt[]},{}) + vertex v1 of property graph gt | ("property graph element",,,"v1 of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,v1}",{}) + vertex v2 of property graph gt | ("property graph element",,,"v2 of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,v2}",{}) +(52 rows) + \a\t SELECT pg_get_propgraphdef('g2'::regclass); CREATE PROPERTY GRAPH create_property_graph_tests.g2 diff --git a/src/test/regress/expected/event_trigger.out b/src/test/regress/expected/event_trigger.out index 065f586310f..ed8d5df397e 100644 --- a/src/test/regress/expected/event_trigger.out +++ b/src/test/regress/expected/event_trigger.out @@ -173,6 +173,23 @@ NOTICE: test_event_trigger: ddl_command_end CREATE USER MAPPING alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; NOTICE: test_event_trigger: ddl_command_end ALTER DEFAULT PRIVILEGES +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE TABLE t2x (i int PRIMARY KEY, j text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); +NOTICE: test_event_trigger: ddl_command_end CREATE PROPERTY GRAPH +DROP PROPERTY GRAPH gx; +NOTICE: test_event_trigger: ddl_command_end DROP PROPERTY GRAPH +DROP TABLE t1x, t2x; +NOTICE: test_event_trigger: ddl_command_end DROP TABLE -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; ERROR: permission denied to change owner of event trigger "regress_event_trigger" diff --git a/src/test/regress/expected/object_address.out b/src/test/regress/expected/object_address.out index 97227d67a54..5e53f0b092e 100644 --- a/src/test/regress/expected/object_address.out +++ b/src/test/regress/expected/object_address.out @@ -67,7 +67,9 @@ DECLARE BEGIN FOR objtype IN VALUES ('toast table'), ('index column'), ('sequence column'), ('toast table column'), ('view column'), ('materialized view column'), - ('property graph element'), ('property graph label'), ('property graph property') + ('property graph element'), ('property graph element label'), + ('property graph label'), ('property graph label property'), + ('property graph property') LOOP BEGIN PERFORM pg_get_object_address(objtype, '{one}', '{}'); @@ -84,7 +86,9 @@ WARNING: error for toast table column: unsupported object type "toast table col WARNING: error for view column: unsupported object type "view column" WARNING: error for materialized view column: unsupported object type "materialized view column" WARNING: error for property graph element: unsupported object type "property graph element" +WARNING: error for property graph element label: unrecognized object type "property graph element label" WARNING: error for property graph label: unsupported object type "property graph label" +WARNING: error for property graph label property: unrecognized object type "property graph label property" WARNING: error for property graph property: unsupported object type "property graph property" -- miscellaneous other errors select * from pg_get_object_address('operator of access method', '{btree,integer_ops,1}', '{int4,bool}'); @@ -593,7 +597,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace @@ -653,6 +659,8 @@ ORDER BY objects.classid, objects.objid, objects.objsubid; ("(""parameter ACL"",,,)")|("(""parameter ACL"",,)")|NULL ("(""property graph element"",,,)")|("(""property graph element"",,)")|NULL ("(""property graph label"",,,)")|("(""property graph label"",,)")|NULL +("(""property graph element label"",,,)")|("(""property graph element label"",,)")|NULL ("(""property graph property"",,,)")|("(""property graph property"",,)")|NULL +("(""property graph label property"",,,)")|("(""property graph label property"",,)")|NULL -- restore normal output mode \a\t diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..9608dd5c4af 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -298,6 +298,29 @@ SELECT (pg_identify_object(classid, objid, objsubid)).* refobjid = 'create_property_graph_tests.g2'::regclass ORDER BY 1, 2, 3, 4; +-- test object address functions with recursive dependency walk +-- covers all property graph object types including indirect dependents +SELECT * +FROM ( + WITH RECURSIVE deps (classid, objid, objsubid, refclassid, refobjid, refobjsubid) AS ( + SELECT classid, objid, objsubid, + refclassid, refobjid, refobjsubid + FROM pg_depend + WHERE refclassid = 'pg_class'::regclass AND + refobjid = 'create_property_graph_tests.gt'::regclass + UNION ALL + SELECT d.classid, d.objid, d.objsubid, + d.refclassid, d.refobjid, d.refobjsubid + FROM pg_depend d + JOIN deps dp ON d.refclassid = dp.classid AND d.refobjid = dp.objid AND d.refobjsubid = dp.objsubid + ) + SELECT pg_describe_object(classid, objid, objsubid) as obj, + pg_identify_object(classid, objid, objsubid) as ident, + pg_identify_object_as_address(classid, objid, objsubid) as addr + FROM deps +) s +ORDER BY obj COLLATE "C", ident::text COLLATE "C"; + \a\t SELECT pg_get_propgraphdef('g2'::regclass); SELECT pg_get_propgraphdef('g3'::regclass); diff --git a/src/test/regress/sql/event_trigger.sql b/src/test/regress/sql/event_trigger.sql index 32e9bb58c5e..271f443378b 100644 --- a/src/test/regress/sql/event_trigger.sql +++ b/src/test/regress/sql/event_trigger.sql @@ -143,6 +143,19 @@ create user mapping for regress_evt_user server useless_server; alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +CREATE TABLE t2x (i int PRIMARY KEY, j text); + +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); + +DROP PROPERTY GRAPH gx; +DROP TABLE t1x, t2x; + -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; diff --git a/src/test/regress/sql/object_address.sql b/src/test/regress/sql/object_address.sql index 1bbe9457c1c..27109d421c7 100644 --- a/src/test/regress/sql/object_address.sql +++ b/src/test/regress/sql/object_address.sql @@ -67,7 +67,9 @@ DECLARE BEGIN FOR objtype IN VALUES ('toast table'), ('index column'), ('sequence column'), ('toast table column'), ('view column'), ('materialized view column'), - ('property graph element'), ('property graph label'), ('property graph property') + ('property graph element'), ('property graph element label'), + ('property graph label'), ('property graph label property'), + ('property graph property') LOOP BEGIN PERFORM pg_get_object_address(objtype, '{one}', '{}'); @@ -282,7 +284,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace -- 2.34.1 --R84XrR4Hgw0dH3Ec-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v3] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-23 09:27 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-23 09:27 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing them to hit the default case and error out with "unsupported object class". During DROP PROPERTY GRAPH, this manifests when an event trigger is active, because pg_event_trigger_ddl_commands() calls these functions. The same code paths are also reachable via pg_identify_object() and pg_identify_object_as_address(). This commit adds the missing cases. Test coverage is added in object_address.sql for these two catalog types and in create_property_graph.sql covering all property graph object types. A test in event_trigger.sql verifies that DROP PROPERTY GRAPH works correctly when an event trigger is active. Author: Bertrand Drouvot <[email protected]> Reviewed-by: Michael Paquier <[email protected]> Reviewed-by: Ashutosh Bapat <[email protected]> Discussion: https://postgr.es/m/aej1DkLwhyZWmtxJ@bdtpg --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 78 ++++++++++++++++ src/test/regress/expected/event_trigger.out | 17 ++++ src/test/regress/expected/object_address.out | 10 +- .../regress/sql/create_property_graph.sql | 23 +++++ src/test/regress/sql/event_trigger.sql | 13 +++ src/test/regress/sql/object_address.sql | 6 +- 7 files changed, 238 insertions(+), 2 deletions(-) 14.7% src/backend/catalog/ 75.5% src/test/regress/expected/ 9.7% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..eb9e17fb727 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -752,6 +752,84 @@ SELECT (pg_identify_object(classid, objid, objsubid)).* type | create_property_graph_tests | g2 | create_property_graph_tests.g2 (21 rows) +-- test object address functions with recursive dependency walk +-- covers all property graph object types including indirect dependents +SELECT * +FROM ( + WITH RECURSIVE deps (classid, objid, objsubid, refclassid, refobjid, refobjsubid) AS ( + SELECT classid, objid, objsubid, + refclassid, refobjid, refobjsubid + FROM pg_depend + WHERE refclassid = 'pg_class'::regclass AND + refobjid = 'create_property_graph_tests.gt'::regclass + UNION ALL + SELECT d.classid, d.objid, d.objsubid, + d.refclassid, d.refobjid, d.refobjsubid + FROM pg_depend d + JOIN deps dp ON d.refclassid = dp.classid AND d.refobjid = dp.objid AND d.refobjsubid = dp.objsubid + ) + SELECT pg_describe_object(classid, objid, objsubid) as obj, + pg_identify_object(classid, objid, objsubid) as ident, + pg_identify_object_as_address(classid, objid, objsubid) as addr + FROM deps +) s +ORDER BY obj COLLATE "C", ident::text COLLATE "C"; + obj | ident | addr +----------------------------------------------------------+----------------------------------------------------------------------------+---------------------------------------------------------------------------- + edge e of property graph gt | ("property graph element",,,"e of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,e}",{}) + edge e of property graph gt | ("property graph element",,,"e of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,e}",{}) + edge e of property graph gt | ("property graph element",,,"e of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of property graph gt | ("property graph label",,,"e of create_property_graph_tests.gt") | ("property graph label","{create_property_graph_tests,gt,e}",{}) + label v1 of property graph gt | ("property graph label",,,"v1 of create_property_graph_tests.gt") | ("property graph label","{create_property_graph_tests,gt,v1}",{}) + label v1 of vertex v1 of property graph gt | ("property graph element label",,,"v1 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v1}",{}) + label v1 of vertex v1 of property graph gt | ("property graph element label",,,"v1 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v1}",{}) + label v2 of property graph gt | ("property graph label",,,"v2 of create_property_graph_tests.gt") | ("property graph label","{create_property_graph_tests,gt,v2}",{}) + label v2 of vertex v2 of property graph gt | ("property graph element label",,,"v2 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v2}",{}) + label v2 of vertex v2 of property graph gt | ("property graph element label",,,"v2 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v2}",{}) + property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property a of property graph gt | ("property graph property",,,"a of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,a}",{}) + property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property b of property graph gt | ("property graph property",,,"b of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,b}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of property graph gt | ("property graph property",,,"c of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,c}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of property graph gt | ("property graph property",,,"k1 of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,k1}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of property graph gt | ("property graph property",,,"k2 of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,k2}",{}) + property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property m of property graph gt | ("property graph property",,,"m of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,m}",{}) + property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property n of property graph gt | ("property graph property",,,"n of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,n}",{}) + type gt | (type,create_property_graph_tests,gt,create_property_graph_tests.gt) | (type,{create_property_graph_tests.gt},{}) + type gt[] | (type,create_property_graph_tests,_gt,create_property_graph_tests.gt[]) | (type,{create_property_graph_tests.gt[]},{}) + vertex v1 of property graph gt | ("property graph element",,,"v1 of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,v1}",{}) + vertex v2 of property graph gt | ("property graph element",,,"v2 of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,v2}",{}) +(52 rows) + \a\t SELECT pg_get_propgraphdef('g2'::regclass); CREATE PROPERTY GRAPH create_property_graph_tests.g2 diff --git a/src/test/regress/expected/event_trigger.out b/src/test/regress/expected/event_trigger.out index 065f586310f..ed8d5df397e 100644 --- a/src/test/regress/expected/event_trigger.out +++ b/src/test/regress/expected/event_trigger.out @@ -173,6 +173,23 @@ NOTICE: test_event_trigger: ddl_command_end CREATE USER MAPPING alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; NOTICE: test_event_trigger: ddl_command_end ALTER DEFAULT PRIVILEGES +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE TABLE t2x (i int PRIMARY KEY, j text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); +NOTICE: test_event_trigger: ddl_command_end CREATE PROPERTY GRAPH +DROP PROPERTY GRAPH gx; +NOTICE: test_event_trigger: ddl_command_end DROP PROPERTY GRAPH +DROP TABLE t1x, t2x; +NOTICE: test_event_trigger: ddl_command_end DROP TABLE -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; ERROR: permission denied to change owner of event trigger "regress_event_trigger" diff --git a/src/test/regress/expected/object_address.out b/src/test/regress/expected/object_address.out index 97227d67a54..5e53f0b092e 100644 --- a/src/test/regress/expected/object_address.out +++ b/src/test/regress/expected/object_address.out @@ -67,7 +67,9 @@ DECLARE BEGIN FOR objtype IN VALUES ('toast table'), ('index column'), ('sequence column'), ('toast table column'), ('view column'), ('materialized view column'), - ('property graph element'), ('property graph label'), ('property graph property') + ('property graph element'), ('property graph element label'), + ('property graph label'), ('property graph label property'), + ('property graph property') LOOP BEGIN PERFORM pg_get_object_address(objtype, '{one}', '{}'); @@ -84,7 +86,9 @@ WARNING: error for toast table column: unsupported object type "toast table col WARNING: error for view column: unsupported object type "view column" WARNING: error for materialized view column: unsupported object type "materialized view column" WARNING: error for property graph element: unsupported object type "property graph element" +WARNING: error for property graph element label: unrecognized object type "property graph element label" WARNING: error for property graph label: unsupported object type "property graph label" +WARNING: error for property graph label property: unrecognized object type "property graph label property" WARNING: error for property graph property: unsupported object type "property graph property" -- miscellaneous other errors select * from pg_get_object_address('operator of access method', '{btree,integer_ops,1}', '{int4,bool}'); @@ -593,7 +597,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace @@ -653,6 +659,8 @@ ORDER BY objects.classid, objects.objid, objects.objsubid; ("(""parameter ACL"",,,)")|("(""parameter ACL"",,)")|NULL ("(""property graph element"",,,)")|("(""property graph element"",,)")|NULL ("(""property graph label"",,,)")|("(""property graph label"",,)")|NULL +("(""property graph element label"",,,)")|("(""property graph element label"",,)")|NULL ("(""property graph property"",,,)")|("(""property graph property"",,)")|NULL +("(""property graph label property"",,,)")|("(""property graph label property"",,)")|NULL -- restore normal output mode \a\t diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..9608dd5c4af 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -298,6 +298,29 @@ SELECT (pg_identify_object(classid, objid, objsubid)).* refobjid = 'create_property_graph_tests.g2'::regclass ORDER BY 1, 2, 3, 4; +-- test object address functions with recursive dependency walk +-- covers all property graph object types including indirect dependents +SELECT * +FROM ( + WITH RECURSIVE deps (classid, objid, objsubid, refclassid, refobjid, refobjsubid) AS ( + SELECT classid, objid, objsubid, + refclassid, refobjid, refobjsubid + FROM pg_depend + WHERE refclassid = 'pg_class'::regclass AND + refobjid = 'create_property_graph_tests.gt'::regclass + UNION ALL + SELECT d.classid, d.objid, d.objsubid, + d.refclassid, d.refobjid, d.refobjsubid + FROM pg_depend d + JOIN deps dp ON d.refclassid = dp.classid AND d.refobjid = dp.objid AND d.refobjsubid = dp.objsubid + ) + SELECT pg_describe_object(classid, objid, objsubid) as obj, + pg_identify_object(classid, objid, objsubid) as ident, + pg_identify_object_as_address(classid, objid, objsubid) as addr + FROM deps +) s +ORDER BY obj COLLATE "C", ident::text COLLATE "C"; + \a\t SELECT pg_get_propgraphdef('g2'::regclass); SELECT pg_get_propgraphdef('g3'::regclass); diff --git a/src/test/regress/sql/event_trigger.sql b/src/test/regress/sql/event_trigger.sql index 32e9bb58c5e..271f443378b 100644 --- a/src/test/regress/sql/event_trigger.sql +++ b/src/test/regress/sql/event_trigger.sql @@ -143,6 +143,19 @@ create user mapping for regress_evt_user server useless_server; alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +CREATE TABLE t2x (i int PRIMARY KEY, j text); + +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); + +DROP PROPERTY GRAPH gx; +DROP TABLE t1x, t2x; + -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; diff --git a/src/test/regress/sql/object_address.sql b/src/test/regress/sql/object_address.sql index 1bbe9457c1c..27109d421c7 100644 --- a/src/test/regress/sql/object_address.sql +++ b/src/test/regress/sql/object_address.sql @@ -67,7 +67,9 @@ DECLARE BEGIN FOR objtype IN VALUES ('toast table'), ('index column'), ('sequence column'), ('toast table column'), ('view column'), ('materialized view column'), - ('property graph element'), ('property graph label'), ('property graph property') + ('property graph element'), ('property graph element label'), + ('property graph label'), ('property graph label property'), + ('property graph property') LOOP BEGIN PERFORM pg_get_object_address(objtype, '{one}', '{}'); @@ -282,7 +284,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace -- 2.34.1 --R84XrR4Hgw0dH3Ec-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v3] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-23 09:27 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-23 09:27 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing them to hit the default case and error out with "unsupported object class". During DROP PROPERTY GRAPH, this manifests when an event trigger is active, because pg_event_trigger_ddl_commands() calls these functions. The same code paths are also reachable via pg_identify_object() and pg_identify_object_as_address(). This commit adds the missing cases. Test coverage is added in object_address.sql for these two catalog types and in create_property_graph.sql covering all property graph object types. A test in event_trigger.sql verifies that DROP PROPERTY GRAPH works correctly when an event trigger is active. Author: Bertrand Drouvot <[email protected]> Reviewed-by: Michael Paquier <[email protected]> Reviewed-by: Ashutosh Bapat <[email protected]> Discussion: https://postgr.es/m/aej1DkLwhyZWmtxJ@bdtpg --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 78 ++++++++++++++++ src/test/regress/expected/event_trigger.out | 17 ++++ src/test/regress/expected/object_address.out | 10 +- .../regress/sql/create_property_graph.sql | 23 +++++ src/test/regress/sql/event_trigger.sql | 13 +++ src/test/regress/sql/object_address.sql | 6 +- 7 files changed, 238 insertions(+), 2 deletions(-) 14.7% src/backend/catalog/ 75.5% src/test/regress/expected/ 9.7% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..eb9e17fb727 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -752,6 +752,84 @@ SELECT (pg_identify_object(classid, objid, objsubid)).* type | create_property_graph_tests | g2 | create_property_graph_tests.g2 (21 rows) +-- test object address functions with recursive dependency walk +-- covers all property graph object types including indirect dependents +SELECT * +FROM ( + WITH RECURSIVE deps (classid, objid, objsubid, refclassid, refobjid, refobjsubid) AS ( + SELECT classid, objid, objsubid, + refclassid, refobjid, refobjsubid + FROM pg_depend + WHERE refclassid = 'pg_class'::regclass AND + refobjid = 'create_property_graph_tests.gt'::regclass + UNION ALL + SELECT d.classid, d.objid, d.objsubid, + d.refclassid, d.refobjid, d.refobjsubid + FROM pg_depend d + JOIN deps dp ON d.refclassid = dp.classid AND d.refobjid = dp.objid AND d.refobjsubid = dp.objsubid + ) + SELECT pg_describe_object(classid, objid, objsubid) as obj, + pg_identify_object(classid, objid, objsubid) as ident, + pg_identify_object_as_address(classid, objid, objsubid) as addr + FROM deps +) s +ORDER BY obj COLLATE "C", ident::text COLLATE "C"; + obj | ident | addr +----------------------------------------------------------+----------------------------------------------------------------------------+---------------------------------------------------------------------------- + edge e of property graph gt | ("property graph element",,,"e of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,e}",{}) + edge e of property graph gt | ("property graph element",,,"e of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,e}",{}) + edge e of property graph gt | ("property graph element",,,"e of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of property graph gt | ("property graph label",,,"e of create_property_graph_tests.gt") | ("property graph label","{create_property_graph_tests,gt,e}",{}) + label v1 of property graph gt | ("property graph label",,,"v1 of create_property_graph_tests.gt") | ("property graph label","{create_property_graph_tests,gt,v1}",{}) + label v1 of vertex v1 of property graph gt | ("property graph element label",,,"v1 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v1}",{}) + label v1 of vertex v1 of property graph gt | ("property graph element label",,,"v1 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v1}",{}) + label v2 of property graph gt | ("property graph label",,,"v2 of create_property_graph_tests.gt") | ("property graph label","{create_property_graph_tests,gt,v2}",{}) + label v2 of vertex v2 of property graph gt | ("property graph element label",,,"v2 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v2}",{}) + label v2 of vertex v2 of property graph gt | ("property graph element label",,,"v2 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v2}",{}) + property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property a of property graph gt | ("property graph property",,,"a of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,a}",{}) + property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property b of property graph gt | ("property graph property",,,"b of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,b}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of property graph gt | ("property graph property",,,"c of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,c}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of property graph gt | ("property graph property",,,"k1 of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,k1}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of property graph gt | ("property graph property",,,"k2 of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,k2}",{}) + property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property m of property graph gt | ("property graph property",,,"m of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,m}",{}) + property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property n of property graph gt | ("property graph property",,,"n of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,n}",{}) + type gt | (type,create_property_graph_tests,gt,create_property_graph_tests.gt) | (type,{create_property_graph_tests.gt},{}) + type gt[] | (type,create_property_graph_tests,_gt,create_property_graph_tests.gt[]) | (type,{create_property_graph_tests.gt[]},{}) + vertex v1 of property graph gt | ("property graph element",,,"v1 of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,v1}",{}) + vertex v2 of property graph gt | ("property graph element",,,"v2 of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,v2}",{}) +(52 rows) + \a\t SELECT pg_get_propgraphdef('g2'::regclass); CREATE PROPERTY GRAPH create_property_graph_tests.g2 diff --git a/src/test/regress/expected/event_trigger.out b/src/test/regress/expected/event_trigger.out index 065f586310f..ed8d5df397e 100644 --- a/src/test/regress/expected/event_trigger.out +++ b/src/test/regress/expected/event_trigger.out @@ -173,6 +173,23 @@ NOTICE: test_event_trigger: ddl_command_end CREATE USER MAPPING alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; NOTICE: test_event_trigger: ddl_command_end ALTER DEFAULT PRIVILEGES +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE TABLE t2x (i int PRIMARY KEY, j text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); +NOTICE: test_event_trigger: ddl_command_end CREATE PROPERTY GRAPH +DROP PROPERTY GRAPH gx; +NOTICE: test_event_trigger: ddl_command_end DROP PROPERTY GRAPH +DROP TABLE t1x, t2x; +NOTICE: test_event_trigger: ddl_command_end DROP TABLE -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; ERROR: permission denied to change owner of event trigger "regress_event_trigger" diff --git a/src/test/regress/expected/object_address.out b/src/test/regress/expected/object_address.out index 97227d67a54..5e53f0b092e 100644 --- a/src/test/regress/expected/object_address.out +++ b/src/test/regress/expected/object_address.out @@ -67,7 +67,9 @@ DECLARE BEGIN FOR objtype IN VALUES ('toast table'), ('index column'), ('sequence column'), ('toast table column'), ('view column'), ('materialized view column'), - ('property graph element'), ('property graph label'), ('property graph property') + ('property graph element'), ('property graph element label'), + ('property graph label'), ('property graph label property'), + ('property graph property') LOOP BEGIN PERFORM pg_get_object_address(objtype, '{one}', '{}'); @@ -84,7 +86,9 @@ WARNING: error for toast table column: unsupported object type "toast table col WARNING: error for view column: unsupported object type "view column" WARNING: error for materialized view column: unsupported object type "materialized view column" WARNING: error for property graph element: unsupported object type "property graph element" +WARNING: error for property graph element label: unrecognized object type "property graph element label" WARNING: error for property graph label: unsupported object type "property graph label" +WARNING: error for property graph label property: unrecognized object type "property graph label property" WARNING: error for property graph property: unsupported object type "property graph property" -- miscellaneous other errors select * from pg_get_object_address('operator of access method', '{btree,integer_ops,1}', '{int4,bool}'); @@ -593,7 +597,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace @@ -653,6 +659,8 @@ ORDER BY objects.classid, objects.objid, objects.objsubid; ("(""parameter ACL"",,,)")|("(""parameter ACL"",,)")|NULL ("(""property graph element"",,,)")|("(""property graph element"",,)")|NULL ("(""property graph label"",,,)")|("(""property graph label"",,)")|NULL +("(""property graph element label"",,,)")|("(""property graph element label"",,)")|NULL ("(""property graph property"",,,)")|("(""property graph property"",,)")|NULL +("(""property graph label property"",,,)")|("(""property graph label property"",,)")|NULL -- restore normal output mode \a\t diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..9608dd5c4af 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -298,6 +298,29 @@ SELECT (pg_identify_object(classid, objid, objsubid)).* refobjid = 'create_property_graph_tests.g2'::regclass ORDER BY 1, 2, 3, 4; +-- test object address functions with recursive dependency walk +-- covers all property graph object types including indirect dependents +SELECT * +FROM ( + WITH RECURSIVE deps (classid, objid, objsubid, refclassid, refobjid, refobjsubid) AS ( + SELECT classid, objid, objsubid, + refclassid, refobjid, refobjsubid + FROM pg_depend + WHERE refclassid = 'pg_class'::regclass AND + refobjid = 'create_property_graph_tests.gt'::regclass + UNION ALL + SELECT d.classid, d.objid, d.objsubid, + d.refclassid, d.refobjid, d.refobjsubid + FROM pg_depend d + JOIN deps dp ON d.refclassid = dp.classid AND d.refobjid = dp.objid AND d.refobjsubid = dp.objsubid + ) + SELECT pg_describe_object(classid, objid, objsubid) as obj, + pg_identify_object(classid, objid, objsubid) as ident, + pg_identify_object_as_address(classid, objid, objsubid) as addr + FROM deps +) s +ORDER BY obj COLLATE "C", ident::text COLLATE "C"; + \a\t SELECT pg_get_propgraphdef('g2'::regclass); SELECT pg_get_propgraphdef('g3'::regclass); diff --git a/src/test/regress/sql/event_trigger.sql b/src/test/regress/sql/event_trigger.sql index 32e9bb58c5e..271f443378b 100644 --- a/src/test/regress/sql/event_trigger.sql +++ b/src/test/regress/sql/event_trigger.sql @@ -143,6 +143,19 @@ create user mapping for regress_evt_user server useless_server; alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +CREATE TABLE t2x (i int PRIMARY KEY, j text); + +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); + +DROP PROPERTY GRAPH gx; +DROP TABLE t1x, t2x; + -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; diff --git a/src/test/regress/sql/object_address.sql b/src/test/regress/sql/object_address.sql index 1bbe9457c1c..27109d421c7 100644 --- a/src/test/regress/sql/object_address.sql +++ b/src/test/regress/sql/object_address.sql @@ -67,7 +67,9 @@ DECLARE BEGIN FOR objtype IN VALUES ('toast table'), ('index column'), ('sequence column'), ('toast table column'), ('view column'), ('materialized view column'), - ('property graph element'), ('property graph label'), ('property graph property') + ('property graph element'), ('property graph element label'), + ('property graph label'), ('property graph label property'), + ('property graph property') LOOP BEGIN PERFORM pg_get_object_address(objtype, '{one}', '{}'); @@ -282,7 +284,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace -- 2.34.1 --R84XrR4Hgw0dH3Ec-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v2] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-23 09:27 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-23 09:27 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing them to hit the default case and error out with "unsupported object class". During DROP PROPERTY GRAPH, this manifests when an event trigger is active, because pg_event_trigger_ddl_commands() calls these functions. The same code paths are also reachable via pg_identify_object() and pg_identify_object_as_address(). This commit adds the missing cases. Test coverage is added in object_address.sql for these two catalog types via the zero-OID test that exercises pg_identify_object() and pg_identify_object_as_address(). A test in event_trigger.sql verifies that DROP PROPERTY GRAPH works correctly when an event trigger is active. Author: Bertrand Drouvot <[email protected]> Reviewed-by: Michael Paquier <[email protected]> Reviewed-by: Ashutosh Bapat <[email protected]> Discussion: https://postgr.es/m/aej1DkLwhyZWmtxJ@bdtpg --- src/backend/catalog/objectaddress.c | 93 ++++++++++++++++++++ src/test/regress/expected/event_trigger.out | 17 ++++ src/test/regress/expected/object_address.out | 4 + src/test/regress/sql/event_trigger.sql | 13 +++ src/test/regress/sql/object_address.sql | 2 + 5 files changed, 129 insertions(+) 62.4% src/backend/catalog/ 25.6% src/test/regress/expected/ 11.8% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/event_trigger.out b/src/test/regress/expected/event_trigger.out index 065f586310f..ed8d5df397e 100644 --- a/src/test/regress/expected/event_trigger.out +++ b/src/test/regress/expected/event_trigger.out @@ -173,6 +173,23 @@ NOTICE: test_event_trigger: ddl_command_end CREATE USER MAPPING alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; NOTICE: test_event_trigger: ddl_command_end ALTER DEFAULT PRIVILEGES +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE TABLE t2x (i int PRIMARY KEY, j text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); +NOTICE: test_event_trigger: ddl_command_end CREATE PROPERTY GRAPH +DROP PROPERTY GRAPH gx; +NOTICE: test_event_trigger: ddl_command_end DROP PROPERTY GRAPH +DROP TABLE t1x, t2x; +NOTICE: test_event_trigger: ddl_command_end DROP TABLE -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; ERROR: permission denied to change owner of event trigger "regress_event_trigger" diff --git a/src/test/regress/expected/object_address.out b/src/test/regress/expected/object_address.out index 97227d67a54..729c3537f25 100644 --- a/src/test/regress/expected/object_address.out +++ b/src/test/regress/expected/object_address.out @@ -593,7 +593,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace @@ -653,6 +655,8 @@ ORDER BY objects.classid, objects.objid, objects.objsubid; ("(""parameter ACL"",,,)")|("(""parameter ACL"",,)")|NULL ("(""property graph element"",,,)")|("(""property graph element"",,)")|NULL ("(""property graph label"",,,)")|("(""property graph label"",,)")|NULL +("(""property graph element label"",,,)")|("(""property graph element label"",,)")|NULL ("(""property graph property"",,,)")|("(""property graph property"",,)")|NULL +("(""property graph label property"",,,)")|("(""property graph label property"",,)")|NULL -- restore normal output mode \a\t diff --git a/src/test/regress/sql/event_trigger.sql b/src/test/regress/sql/event_trigger.sql index 32e9bb58c5e..271f443378b 100644 --- a/src/test/regress/sql/event_trigger.sql +++ b/src/test/regress/sql/event_trigger.sql @@ -143,6 +143,19 @@ create user mapping for regress_evt_user server useless_server; alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +CREATE TABLE t2x (i int PRIMARY KEY, j text); + +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); + +DROP PROPERTY GRAPH gx; +DROP TABLE t1x, t2x; + -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; diff --git a/src/test/regress/sql/object_address.sql b/src/test/regress/sql/object_address.sql index 1bbe9457c1c..620dacf1045 100644 --- a/src/test/regress/sql/object_address.sql +++ b/src/test/regress/sql/object_address.sql @@ -282,7 +282,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace -- 2.34.1 --gtUR827Uq8d5gVsQ-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v2] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-23 09:27 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-23 09:27 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing them to hit the default case and error out with "unsupported object class". During DROP PROPERTY GRAPH, this manifests when an event trigger is active, because pg_event_trigger_ddl_commands() calls these functions. The same code paths are also reachable via pg_identify_object() and pg_identify_object_as_address(). This commit adds the missing cases. Test coverage is added in object_address.sql for these two catalog types via the zero-OID test that exercises pg_identify_object() and pg_identify_object_as_address(). A test in event_trigger.sql verifies that DROP PROPERTY GRAPH works correctly when an event trigger is active. Author: Bertrand Drouvot <[email protected]> Reviewed-by: Michael Paquier <[email protected]> Reviewed-by: Ashutosh Bapat <[email protected]> Discussion: https://postgr.es/m/aej1DkLwhyZWmtxJ@bdtpg --- src/backend/catalog/objectaddress.c | 93 ++++++++++++++++++++ src/test/regress/expected/event_trigger.out | 17 ++++ src/test/regress/expected/object_address.out | 4 + src/test/regress/sql/event_trigger.sql | 13 +++ src/test/regress/sql/object_address.sql | 2 + 5 files changed, 129 insertions(+) 62.4% src/backend/catalog/ 25.6% src/test/regress/expected/ 11.8% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/event_trigger.out b/src/test/regress/expected/event_trigger.out index 065f586310f..ed8d5df397e 100644 --- a/src/test/regress/expected/event_trigger.out +++ b/src/test/regress/expected/event_trigger.out @@ -173,6 +173,23 @@ NOTICE: test_event_trigger: ddl_command_end CREATE USER MAPPING alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; NOTICE: test_event_trigger: ddl_command_end ALTER DEFAULT PRIVILEGES +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE TABLE t2x (i int PRIMARY KEY, j text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); +NOTICE: test_event_trigger: ddl_command_end CREATE PROPERTY GRAPH +DROP PROPERTY GRAPH gx; +NOTICE: test_event_trigger: ddl_command_end DROP PROPERTY GRAPH +DROP TABLE t1x, t2x; +NOTICE: test_event_trigger: ddl_command_end DROP TABLE -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; ERROR: permission denied to change owner of event trigger "regress_event_trigger" diff --git a/src/test/regress/expected/object_address.out b/src/test/regress/expected/object_address.out index 97227d67a54..729c3537f25 100644 --- a/src/test/regress/expected/object_address.out +++ b/src/test/regress/expected/object_address.out @@ -593,7 +593,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace @@ -653,6 +655,8 @@ ORDER BY objects.classid, objects.objid, objects.objsubid; ("(""parameter ACL"",,,)")|("(""parameter ACL"",,)")|NULL ("(""property graph element"",,,)")|("(""property graph element"",,)")|NULL ("(""property graph label"",,,)")|("(""property graph label"",,)")|NULL +("(""property graph element label"",,,)")|("(""property graph element label"",,)")|NULL ("(""property graph property"",,,)")|("(""property graph property"",,)")|NULL +("(""property graph label property"",,,)")|("(""property graph label property"",,)")|NULL -- restore normal output mode \a\t diff --git a/src/test/regress/sql/event_trigger.sql b/src/test/regress/sql/event_trigger.sql index 32e9bb58c5e..271f443378b 100644 --- a/src/test/regress/sql/event_trigger.sql +++ b/src/test/regress/sql/event_trigger.sql @@ -143,6 +143,19 @@ create user mapping for regress_evt_user server useless_server; alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +CREATE TABLE t2x (i int PRIMARY KEY, j text); + +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); + +DROP PROPERTY GRAPH gx; +DROP TABLE t1x, t2x; + -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; diff --git a/src/test/regress/sql/object_address.sql b/src/test/regress/sql/object_address.sql index 1bbe9457c1c..620dacf1045 100644 --- a/src/test/regress/sql/object_address.sql +++ b/src/test/regress/sql/object_address.sql @@ -282,7 +282,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace -- 2.34.1 --gtUR827Uq8d5gVsQ-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v2] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-23 09:27 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-23 09:27 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing them to hit the default case and error out with "unsupported object class". During DROP PROPERTY GRAPH, this manifests when an event trigger is active, because pg_event_trigger_ddl_commands() calls these functions. The same code paths are also reachable via pg_identify_object() and pg_identify_object_as_address(). This commit adds the missing cases. Test coverage is added in object_address.sql for these two catalog types via the zero-OID test that exercises pg_identify_object() and pg_identify_object_as_address(). A test in event_trigger.sql verifies that DROP PROPERTY GRAPH works correctly when an event trigger is active. Author: Bertrand Drouvot <[email protected]> Reviewed-by: Michael Paquier <[email protected]> Reviewed-by: Ashutosh Bapat <[email protected]> Discussion: https://postgr.es/m/aej1DkLwhyZWmtxJ@bdtpg --- src/backend/catalog/objectaddress.c | 93 ++++++++++++++++++++ src/test/regress/expected/event_trigger.out | 17 ++++ src/test/regress/expected/object_address.out | 4 + src/test/regress/sql/event_trigger.sql | 13 +++ src/test/regress/sql/object_address.sql | 2 + 5 files changed, 129 insertions(+) 62.4% src/backend/catalog/ 25.6% src/test/regress/expected/ 11.8% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/event_trigger.out b/src/test/regress/expected/event_trigger.out index 065f586310f..ed8d5df397e 100644 --- a/src/test/regress/expected/event_trigger.out +++ b/src/test/regress/expected/event_trigger.out @@ -173,6 +173,23 @@ NOTICE: test_event_trigger: ddl_command_end CREATE USER MAPPING alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; NOTICE: test_event_trigger: ddl_command_end ALTER DEFAULT PRIVILEGES +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE TABLE t2x (i int PRIMARY KEY, j text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); +NOTICE: test_event_trigger: ddl_command_end CREATE PROPERTY GRAPH +DROP PROPERTY GRAPH gx; +NOTICE: test_event_trigger: ddl_command_end DROP PROPERTY GRAPH +DROP TABLE t1x, t2x; +NOTICE: test_event_trigger: ddl_command_end DROP TABLE -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; ERROR: permission denied to change owner of event trigger "regress_event_trigger" diff --git a/src/test/regress/expected/object_address.out b/src/test/regress/expected/object_address.out index 97227d67a54..729c3537f25 100644 --- a/src/test/regress/expected/object_address.out +++ b/src/test/regress/expected/object_address.out @@ -593,7 +593,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace @@ -653,6 +655,8 @@ ORDER BY objects.classid, objects.objid, objects.objsubid; ("(""parameter ACL"",,,)")|("(""parameter ACL"",,)")|NULL ("(""property graph element"",,,)")|("(""property graph element"",,)")|NULL ("(""property graph label"",,,)")|("(""property graph label"",,)")|NULL +("(""property graph element label"",,,)")|("(""property graph element label"",,)")|NULL ("(""property graph property"",,,)")|("(""property graph property"",,)")|NULL +("(""property graph label property"",,,)")|("(""property graph label property"",,)")|NULL -- restore normal output mode \a\t diff --git a/src/test/regress/sql/event_trigger.sql b/src/test/regress/sql/event_trigger.sql index 32e9bb58c5e..271f443378b 100644 --- a/src/test/regress/sql/event_trigger.sql +++ b/src/test/regress/sql/event_trigger.sql @@ -143,6 +143,19 @@ create user mapping for regress_evt_user server useless_server; alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +CREATE TABLE t2x (i int PRIMARY KEY, j text); + +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); + +DROP PROPERTY GRAPH gx; +DROP TABLE t1x, t2x; + -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; diff --git a/src/test/regress/sql/object_address.sql b/src/test/regress/sql/object_address.sql index 1bbe9457c1c..620dacf1045 100644 --- a/src/test/regress/sql/object_address.sql +++ b/src/test/regress/sql/object_address.sql @@ -282,7 +282,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace -- 2.34.1 --gtUR827Uq8d5gVsQ-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v3] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-23 09:27 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-23 09:27 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing them to hit the default case and error out with "unsupported object class". During DROP PROPERTY GRAPH, this manifests when an event trigger is active, because pg_event_trigger_ddl_commands() calls these functions. The same code paths are also reachable via pg_identify_object() and pg_identify_object_as_address(). This commit adds the missing cases. Test coverage is added in object_address.sql for these two catalog types and in create_property_graph.sql covering all property graph object types. A test in event_trigger.sql verifies that DROP PROPERTY GRAPH works correctly when an event trigger is active. Author: Bertrand Drouvot <[email protected]> Reviewed-by: Michael Paquier <[email protected]> Reviewed-by: Ashutosh Bapat <[email protected]> Discussion: https://postgr.es/m/aej1DkLwhyZWmtxJ@bdtpg --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 78 ++++++++++++++++ src/test/regress/expected/event_trigger.out | 17 ++++ src/test/regress/expected/object_address.out | 10 +- .../regress/sql/create_property_graph.sql | 23 +++++ src/test/regress/sql/event_trigger.sql | 13 +++ src/test/regress/sql/object_address.sql | 6 +- 7 files changed, 238 insertions(+), 2 deletions(-) 14.7% src/backend/catalog/ 75.5% src/test/regress/expected/ 9.7% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..eb9e17fb727 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -752,6 +752,84 @@ SELECT (pg_identify_object(classid, objid, objsubid)).* type | create_property_graph_tests | g2 | create_property_graph_tests.g2 (21 rows) +-- test object address functions with recursive dependency walk +-- covers all property graph object types including indirect dependents +SELECT * +FROM ( + WITH RECURSIVE deps (classid, objid, objsubid, refclassid, refobjid, refobjsubid) AS ( + SELECT classid, objid, objsubid, + refclassid, refobjid, refobjsubid + FROM pg_depend + WHERE refclassid = 'pg_class'::regclass AND + refobjid = 'create_property_graph_tests.gt'::regclass + UNION ALL + SELECT d.classid, d.objid, d.objsubid, + d.refclassid, d.refobjid, d.refobjsubid + FROM pg_depend d + JOIN deps dp ON d.refclassid = dp.classid AND d.refobjid = dp.objid AND d.refobjsubid = dp.objsubid + ) + SELECT pg_describe_object(classid, objid, objsubid) as obj, + pg_identify_object(classid, objid, objsubid) as ident, + pg_identify_object_as_address(classid, objid, objsubid) as addr + FROM deps +) s +ORDER BY obj COLLATE "C", ident::text COLLATE "C"; + obj | ident | addr +----------------------------------------------------------+----------------------------------------------------------------------------+---------------------------------------------------------------------------- + edge e of property graph gt | ("property graph element",,,"e of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,e}",{}) + edge e of property graph gt | ("property graph element",,,"e of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,e}",{}) + edge e of property graph gt | ("property graph element",,,"e of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of property graph gt | ("property graph label",,,"e of create_property_graph_tests.gt") | ("property graph label","{create_property_graph_tests,gt,e}",{}) + label v1 of property graph gt | ("property graph label",,,"v1 of create_property_graph_tests.gt") | ("property graph label","{create_property_graph_tests,gt,v1}",{}) + label v1 of vertex v1 of property graph gt | ("property graph element label",,,"v1 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v1}",{}) + label v1 of vertex v1 of property graph gt | ("property graph element label",,,"v1 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v1}",{}) + label v2 of property graph gt | ("property graph label",,,"v2 of create_property_graph_tests.gt") | ("property graph label","{create_property_graph_tests,gt,v2}",{}) + label v2 of vertex v2 of property graph gt | ("property graph element label",,,"v2 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v2}",{}) + label v2 of vertex v2 of property graph gt | ("property graph element label",,,"v2 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v2}",{}) + property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property a of property graph gt | ("property graph property",,,"a of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,a}",{}) + property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property b of property graph gt | ("property graph property",,,"b of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,b}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of property graph gt | ("property graph property",,,"c of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,c}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of property graph gt | ("property graph property",,,"k1 of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,k1}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of property graph gt | ("property graph property",,,"k2 of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,k2}",{}) + property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property m of property graph gt | ("property graph property",,,"m of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,m}",{}) + property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property n of property graph gt | ("property graph property",,,"n of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,n}",{}) + type gt | (type,create_property_graph_tests,gt,create_property_graph_tests.gt) | (type,{create_property_graph_tests.gt},{}) + type gt[] | (type,create_property_graph_tests,_gt,create_property_graph_tests.gt[]) | (type,{create_property_graph_tests.gt[]},{}) + vertex v1 of property graph gt | ("property graph element",,,"v1 of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,v1}",{}) + vertex v2 of property graph gt | ("property graph element",,,"v2 of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,v2}",{}) +(52 rows) + \a\t SELECT pg_get_propgraphdef('g2'::regclass); CREATE PROPERTY GRAPH create_property_graph_tests.g2 diff --git a/src/test/regress/expected/event_trigger.out b/src/test/regress/expected/event_trigger.out index 065f586310f..ed8d5df397e 100644 --- a/src/test/regress/expected/event_trigger.out +++ b/src/test/regress/expected/event_trigger.out @@ -173,6 +173,23 @@ NOTICE: test_event_trigger: ddl_command_end CREATE USER MAPPING alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; NOTICE: test_event_trigger: ddl_command_end ALTER DEFAULT PRIVILEGES +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE TABLE t2x (i int PRIMARY KEY, j text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); +NOTICE: test_event_trigger: ddl_command_end CREATE PROPERTY GRAPH +DROP PROPERTY GRAPH gx; +NOTICE: test_event_trigger: ddl_command_end DROP PROPERTY GRAPH +DROP TABLE t1x, t2x; +NOTICE: test_event_trigger: ddl_command_end DROP TABLE -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; ERROR: permission denied to change owner of event trigger "regress_event_trigger" diff --git a/src/test/regress/expected/object_address.out b/src/test/regress/expected/object_address.out index 97227d67a54..5e53f0b092e 100644 --- a/src/test/regress/expected/object_address.out +++ b/src/test/regress/expected/object_address.out @@ -67,7 +67,9 @@ DECLARE BEGIN FOR objtype IN VALUES ('toast table'), ('index column'), ('sequence column'), ('toast table column'), ('view column'), ('materialized view column'), - ('property graph element'), ('property graph label'), ('property graph property') + ('property graph element'), ('property graph element label'), + ('property graph label'), ('property graph label property'), + ('property graph property') LOOP BEGIN PERFORM pg_get_object_address(objtype, '{one}', '{}'); @@ -84,7 +86,9 @@ WARNING: error for toast table column: unsupported object type "toast table col WARNING: error for view column: unsupported object type "view column" WARNING: error for materialized view column: unsupported object type "materialized view column" WARNING: error for property graph element: unsupported object type "property graph element" +WARNING: error for property graph element label: unrecognized object type "property graph element label" WARNING: error for property graph label: unsupported object type "property graph label" +WARNING: error for property graph label property: unrecognized object type "property graph label property" WARNING: error for property graph property: unsupported object type "property graph property" -- miscellaneous other errors select * from pg_get_object_address('operator of access method', '{btree,integer_ops,1}', '{int4,bool}'); @@ -593,7 +597,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace @@ -653,6 +659,8 @@ ORDER BY objects.classid, objects.objid, objects.objsubid; ("(""parameter ACL"",,,)")|("(""parameter ACL"",,)")|NULL ("(""property graph element"",,,)")|("(""property graph element"",,)")|NULL ("(""property graph label"",,,)")|("(""property graph label"",,)")|NULL +("(""property graph element label"",,,)")|("(""property graph element label"",,)")|NULL ("(""property graph property"",,,)")|("(""property graph property"",,)")|NULL +("(""property graph label property"",,,)")|("(""property graph label property"",,)")|NULL -- restore normal output mode \a\t diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..9608dd5c4af 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -298,6 +298,29 @@ SELECT (pg_identify_object(classid, objid, objsubid)).* refobjid = 'create_property_graph_tests.g2'::regclass ORDER BY 1, 2, 3, 4; +-- test object address functions with recursive dependency walk +-- covers all property graph object types including indirect dependents +SELECT * +FROM ( + WITH RECURSIVE deps (classid, objid, objsubid, refclassid, refobjid, refobjsubid) AS ( + SELECT classid, objid, objsubid, + refclassid, refobjid, refobjsubid + FROM pg_depend + WHERE refclassid = 'pg_class'::regclass AND + refobjid = 'create_property_graph_tests.gt'::regclass + UNION ALL + SELECT d.classid, d.objid, d.objsubid, + d.refclassid, d.refobjid, d.refobjsubid + FROM pg_depend d + JOIN deps dp ON d.refclassid = dp.classid AND d.refobjid = dp.objid AND d.refobjsubid = dp.objsubid + ) + SELECT pg_describe_object(classid, objid, objsubid) as obj, + pg_identify_object(classid, objid, objsubid) as ident, + pg_identify_object_as_address(classid, objid, objsubid) as addr + FROM deps +) s +ORDER BY obj COLLATE "C", ident::text COLLATE "C"; + \a\t SELECT pg_get_propgraphdef('g2'::regclass); SELECT pg_get_propgraphdef('g3'::regclass); diff --git a/src/test/regress/sql/event_trigger.sql b/src/test/regress/sql/event_trigger.sql index 32e9bb58c5e..271f443378b 100644 --- a/src/test/regress/sql/event_trigger.sql +++ b/src/test/regress/sql/event_trigger.sql @@ -143,6 +143,19 @@ create user mapping for regress_evt_user server useless_server; alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +CREATE TABLE t2x (i int PRIMARY KEY, j text); + +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); + +DROP PROPERTY GRAPH gx; +DROP TABLE t1x, t2x; + -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; diff --git a/src/test/regress/sql/object_address.sql b/src/test/regress/sql/object_address.sql index 1bbe9457c1c..27109d421c7 100644 --- a/src/test/regress/sql/object_address.sql +++ b/src/test/regress/sql/object_address.sql @@ -67,7 +67,9 @@ DECLARE BEGIN FOR objtype IN VALUES ('toast table'), ('index column'), ('sequence column'), ('toast table column'), ('view column'), ('materialized view column'), - ('property graph element'), ('property graph label'), ('property graph property') + ('property graph element'), ('property graph element label'), + ('property graph label'), ('property graph label property'), + ('property graph property') LOOP BEGIN PERFORM pg_get_object_address(objtype, '{one}', '{}'); @@ -282,7 +284,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace -- 2.34.1 --R84XrR4Hgw0dH3Ec-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v2] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-23 09:27 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-23 09:27 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing them to hit the default case and error out with "unsupported object class". During DROP PROPERTY GRAPH, this manifests when an event trigger is active, because pg_event_trigger_ddl_commands() calls these functions. The same code paths are also reachable via pg_identify_object() and pg_identify_object_as_address(). This commit adds the missing cases. Test coverage is added in object_address.sql for these two catalog types via the zero-OID test that exercises pg_identify_object() and pg_identify_object_as_address(). A test in event_trigger.sql verifies that DROP PROPERTY GRAPH works correctly when an event trigger is active. Author: Bertrand Drouvot <[email protected]> Reviewed-by: Michael Paquier <[email protected]> Reviewed-by: Ashutosh Bapat <[email protected]> Discussion: https://postgr.es/m/aej1DkLwhyZWmtxJ@bdtpg --- src/backend/catalog/objectaddress.c | 93 ++++++++++++++++++++ src/test/regress/expected/event_trigger.out | 17 ++++ src/test/regress/expected/object_address.out | 4 + src/test/regress/sql/event_trigger.sql | 13 +++ src/test/regress/sql/object_address.sql | 2 + 5 files changed, 129 insertions(+) 62.4% src/backend/catalog/ 25.6% src/test/regress/expected/ 11.8% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/event_trigger.out b/src/test/regress/expected/event_trigger.out index 065f586310f..ed8d5df397e 100644 --- a/src/test/regress/expected/event_trigger.out +++ b/src/test/regress/expected/event_trigger.out @@ -173,6 +173,23 @@ NOTICE: test_event_trigger: ddl_command_end CREATE USER MAPPING alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; NOTICE: test_event_trigger: ddl_command_end ALTER DEFAULT PRIVILEGES +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE TABLE t2x (i int PRIMARY KEY, j text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); +NOTICE: test_event_trigger: ddl_command_end CREATE PROPERTY GRAPH +DROP PROPERTY GRAPH gx; +NOTICE: test_event_trigger: ddl_command_end DROP PROPERTY GRAPH +DROP TABLE t1x, t2x; +NOTICE: test_event_trigger: ddl_command_end DROP TABLE -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; ERROR: permission denied to change owner of event trigger "regress_event_trigger" diff --git a/src/test/regress/expected/object_address.out b/src/test/regress/expected/object_address.out index 97227d67a54..729c3537f25 100644 --- a/src/test/regress/expected/object_address.out +++ b/src/test/regress/expected/object_address.out @@ -593,7 +593,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace @@ -653,6 +655,8 @@ ORDER BY objects.classid, objects.objid, objects.objsubid; ("(""parameter ACL"",,,)")|("(""parameter ACL"",,)")|NULL ("(""property graph element"",,,)")|("(""property graph element"",,)")|NULL ("(""property graph label"",,,)")|("(""property graph label"",,)")|NULL +("(""property graph element label"",,,)")|("(""property graph element label"",,)")|NULL ("(""property graph property"",,,)")|("(""property graph property"",,)")|NULL +("(""property graph label property"",,,)")|("(""property graph label property"",,)")|NULL -- restore normal output mode \a\t diff --git a/src/test/regress/sql/event_trigger.sql b/src/test/regress/sql/event_trigger.sql index 32e9bb58c5e..271f443378b 100644 --- a/src/test/regress/sql/event_trigger.sql +++ b/src/test/regress/sql/event_trigger.sql @@ -143,6 +143,19 @@ create user mapping for regress_evt_user server useless_server; alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +CREATE TABLE t2x (i int PRIMARY KEY, j text); + +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); + +DROP PROPERTY GRAPH gx; +DROP TABLE t1x, t2x; + -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; diff --git a/src/test/regress/sql/object_address.sql b/src/test/regress/sql/object_address.sql index 1bbe9457c1c..620dacf1045 100644 --- a/src/test/regress/sql/object_address.sql +++ b/src/test/regress/sql/object_address.sql @@ -282,7 +282,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace -- 2.34.1 --gtUR827Uq8d5gVsQ-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v3] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-23 09:27 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-23 09:27 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing them to hit the default case and error out with "unsupported object class". During DROP PROPERTY GRAPH, this manifests when an event trigger is active, because pg_event_trigger_ddl_commands() calls these functions. The same code paths are also reachable via pg_identify_object() and pg_identify_object_as_address(). This commit adds the missing cases. Test coverage is added in object_address.sql for these two catalog types and in create_property_graph.sql covering all property graph object types. A test in event_trigger.sql verifies that DROP PROPERTY GRAPH works correctly when an event trigger is active. Author: Bertrand Drouvot <[email protected]> Reviewed-by: Michael Paquier <[email protected]> Reviewed-by: Ashutosh Bapat <[email protected]> Discussion: https://postgr.es/m/aej1DkLwhyZWmtxJ@bdtpg --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 78 ++++++++++++++++ src/test/regress/expected/event_trigger.out | 17 ++++ src/test/regress/expected/object_address.out | 10 +- .../regress/sql/create_property_graph.sql | 23 +++++ src/test/regress/sql/event_trigger.sql | 13 +++ src/test/regress/sql/object_address.sql | 6 +- 7 files changed, 238 insertions(+), 2 deletions(-) 14.7% src/backend/catalog/ 75.5% src/test/regress/expected/ 9.7% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..eb9e17fb727 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -752,6 +752,84 @@ SELECT (pg_identify_object(classid, objid, objsubid)).* type | create_property_graph_tests | g2 | create_property_graph_tests.g2 (21 rows) +-- test object address functions with recursive dependency walk +-- covers all property graph object types including indirect dependents +SELECT * +FROM ( + WITH RECURSIVE deps (classid, objid, objsubid, refclassid, refobjid, refobjsubid) AS ( + SELECT classid, objid, objsubid, + refclassid, refobjid, refobjsubid + FROM pg_depend + WHERE refclassid = 'pg_class'::regclass AND + refobjid = 'create_property_graph_tests.gt'::regclass + UNION ALL + SELECT d.classid, d.objid, d.objsubid, + d.refclassid, d.refobjid, d.refobjsubid + FROM pg_depend d + JOIN deps dp ON d.refclassid = dp.classid AND d.refobjid = dp.objid AND d.refobjsubid = dp.objsubid + ) + SELECT pg_describe_object(classid, objid, objsubid) as obj, + pg_identify_object(classid, objid, objsubid) as ident, + pg_identify_object_as_address(classid, objid, objsubid) as addr + FROM deps +) s +ORDER BY obj COLLATE "C", ident::text COLLATE "C"; + obj | ident | addr +----------------------------------------------------------+----------------------------------------------------------------------------+---------------------------------------------------------------------------- + edge e of property graph gt | ("property graph element",,,"e of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,e}",{}) + edge e of property graph gt | ("property graph element",,,"e of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,e}",{}) + edge e of property graph gt | ("property graph element",,,"e of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of property graph gt | ("property graph label",,,"e of create_property_graph_tests.gt") | ("property graph label","{create_property_graph_tests,gt,e}",{}) + label v1 of property graph gt | ("property graph label",,,"v1 of create_property_graph_tests.gt") | ("property graph label","{create_property_graph_tests,gt,v1}",{}) + label v1 of vertex v1 of property graph gt | ("property graph element label",,,"v1 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v1}",{}) + label v1 of vertex v1 of property graph gt | ("property graph element label",,,"v1 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v1}",{}) + label v2 of property graph gt | ("property graph label",,,"v2 of create_property_graph_tests.gt") | ("property graph label","{create_property_graph_tests,gt,v2}",{}) + label v2 of vertex v2 of property graph gt | ("property graph element label",,,"v2 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v2}",{}) + label v2 of vertex v2 of property graph gt | ("property graph element label",,,"v2 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v2}",{}) + property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property a of property graph gt | ("property graph property",,,"a of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,a}",{}) + property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property b of property graph gt | ("property graph property",,,"b of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,b}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of property graph gt | ("property graph property",,,"c of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,c}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of property graph gt | ("property graph property",,,"k1 of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,k1}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of property graph gt | ("property graph property",,,"k2 of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,k2}",{}) + property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property m of property graph gt | ("property graph property",,,"m of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,m}",{}) + property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property n of property graph gt | ("property graph property",,,"n of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,n}",{}) + type gt | (type,create_property_graph_tests,gt,create_property_graph_tests.gt) | (type,{create_property_graph_tests.gt},{}) + type gt[] | (type,create_property_graph_tests,_gt,create_property_graph_tests.gt[]) | (type,{create_property_graph_tests.gt[]},{}) + vertex v1 of property graph gt | ("property graph element",,,"v1 of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,v1}",{}) + vertex v2 of property graph gt | ("property graph element",,,"v2 of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,v2}",{}) +(52 rows) + \a\t SELECT pg_get_propgraphdef('g2'::regclass); CREATE PROPERTY GRAPH create_property_graph_tests.g2 diff --git a/src/test/regress/expected/event_trigger.out b/src/test/regress/expected/event_trigger.out index 065f586310f..ed8d5df397e 100644 --- a/src/test/regress/expected/event_trigger.out +++ b/src/test/regress/expected/event_trigger.out @@ -173,6 +173,23 @@ NOTICE: test_event_trigger: ddl_command_end CREATE USER MAPPING alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; NOTICE: test_event_trigger: ddl_command_end ALTER DEFAULT PRIVILEGES +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE TABLE t2x (i int PRIMARY KEY, j text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); +NOTICE: test_event_trigger: ddl_command_end CREATE PROPERTY GRAPH +DROP PROPERTY GRAPH gx; +NOTICE: test_event_trigger: ddl_command_end DROP PROPERTY GRAPH +DROP TABLE t1x, t2x; +NOTICE: test_event_trigger: ddl_command_end DROP TABLE -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; ERROR: permission denied to change owner of event trigger "regress_event_trigger" diff --git a/src/test/regress/expected/object_address.out b/src/test/regress/expected/object_address.out index 97227d67a54..5e53f0b092e 100644 --- a/src/test/regress/expected/object_address.out +++ b/src/test/regress/expected/object_address.out @@ -67,7 +67,9 @@ DECLARE BEGIN FOR objtype IN VALUES ('toast table'), ('index column'), ('sequence column'), ('toast table column'), ('view column'), ('materialized view column'), - ('property graph element'), ('property graph label'), ('property graph property') + ('property graph element'), ('property graph element label'), + ('property graph label'), ('property graph label property'), + ('property graph property') LOOP BEGIN PERFORM pg_get_object_address(objtype, '{one}', '{}'); @@ -84,7 +86,9 @@ WARNING: error for toast table column: unsupported object type "toast table col WARNING: error for view column: unsupported object type "view column" WARNING: error for materialized view column: unsupported object type "materialized view column" WARNING: error for property graph element: unsupported object type "property graph element" +WARNING: error for property graph element label: unrecognized object type "property graph element label" WARNING: error for property graph label: unsupported object type "property graph label" +WARNING: error for property graph label property: unrecognized object type "property graph label property" WARNING: error for property graph property: unsupported object type "property graph property" -- miscellaneous other errors select * from pg_get_object_address('operator of access method', '{btree,integer_ops,1}', '{int4,bool}'); @@ -593,7 +597,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace @@ -653,6 +659,8 @@ ORDER BY objects.classid, objects.objid, objects.objsubid; ("(""parameter ACL"",,,)")|("(""parameter ACL"",,)")|NULL ("(""property graph element"",,,)")|("(""property graph element"",,)")|NULL ("(""property graph label"",,,)")|("(""property graph label"",,)")|NULL +("(""property graph element label"",,,)")|("(""property graph element label"",,)")|NULL ("(""property graph property"",,,)")|("(""property graph property"",,)")|NULL +("(""property graph label property"",,,)")|("(""property graph label property"",,)")|NULL -- restore normal output mode \a\t diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..9608dd5c4af 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -298,6 +298,29 @@ SELECT (pg_identify_object(classid, objid, objsubid)).* refobjid = 'create_property_graph_tests.g2'::regclass ORDER BY 1, 2, 3, 4; +-- test object address functions with recursive dependency walk +-- covers all property graph object types including indirect dependents +SELECT * +FROM ( + WITH RECURSIVE deps (classid, objid, objsubid, refclassid, refobjid, refobjsubid) AS ( + SELECT classid, objid, objsubid, + refclassid, refobjid, refobjsubid + FROM pg_depend + WHERE refclassid = 'pg_class'::regclass AND + refobjid = 'create_property_graph_tests.gt'::regclass + UNION ALL + SELECT d.classid, d.objid, d.objsubid, + d.refclassid, d.refobjid, d.refobjsubid + FROM pg_depend d + JOIN deps dp ON d.refclassid = dp.classid AND d.refobjid = dp.objid AND d.refobjsubid = dp.objsubid + ) + SELECT pg_describe_object(classid, objid, objsubid) as obj, + pg_identify_object(classid, objid, objsubid) as ident, + pg_identify_object_as_address(classid, objid, objsubid) as addr + FROM deps +) s +ORDER BY obj COLLATE "C", ident::text COLLATE "C"; + \a\t SELECT pg_get_propgraphdef('g2'::regclass); SELECT pg_get_propgraphdef('g3'::regclass); diff --git a/src/test/regress/sql/event_trigger.sql b/src/test/regress/sql/event_trigger.sql index 32e9bb58c5e..271f443378b 100644 --- a/src/test/regress/sql/event_trigger.sql +++ b/src/test/regress/sql/event_trigger.sql @@ -143,6 +143,19 @@ create user mapping for regress_evt_user server useless_server; alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +CREATE TABLE t2x (i int PRIMARY KEY, j text); + +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); + +DROP PROPERTY GRAPH gx; +DROP TABLE t1x, t2x; + -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; diff --git a/src/test/regress/sql/object_address.sql b/src/test/regress/sql/object_address.sql index 1bbe9457c1c..27109d421c7 100644 --- a/src/test/regress/sql/object_address.sql +++ b/src/test/regress/sql/object_address.sql @@ -67,7 +67,9 @@ DECLARE BEGIN FOR objtype IN VALUES ('toast table'), ('index column'), ('sequence column'), ('toast table column'), ('view column'), ('materialized view column'), - ('property graph element'), ('property graph label'), ('property graph property') + ('property graph element'), ('property graph element label'), + ('property graph label'), ('property graph label property'), + ('property graph property') LOOP BEGIN PERFORM pg_get_object_address(objtype, '{one}', '{}'); @@ -282,7 +284,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace -- 2.34.1 --R84XrR4Hgw0dH3Ec-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v3] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-23 09:27 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-23 09:27 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing them to hit the default case and error out with "unsupported object class". During DROP PROPERTY GRAPH, this manifests when an event trigger is active, because pg_event_trigger_ddl_commands() calls these functions. The same code paths are also reachable via pg_identify_object() and pg_identify_object_as_address(). This commit adds the missing cases. Test coverage is added in object_address.sql for these two catalog types and in create_property_graph.sql covering all property graph object types. A test in event_trigger.sql verifies that DROP PROPERTY GRAPH works correctly when an event trigger is active. Author: Bertrand Drouvot <[email protected]> Reviewed-by: Michael Paquier <[email protected]> Reviewed-by: Ashutosh Bapat <[email protected]> Discussion: https://postgr.es/m/aej1DkLwhyZWmtxJ@bdtpg --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 78 ++++++++++++++++ src/test/regress/expected/event_trigger.out | 17 ++++ src/test/regress/expected/object_address.out | 10 +- .../regress/sql/create_property_graph.sql | 23 +++++ src/test/regress/sql/event_trigger.sql | 13 +++ src/test/regress/sql/object_address.sql | 6 +- 7 files changed, 238 insertions(+), 2 deletions(-) 14.7% src/backend/catalog/ 75.5% src/test/regress/expected/ 9.7% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..eb9e17fb727 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -752,6 +752,84 @@ SELECT (pg_identify_object(classid, objid, objsubid)).* type | create_property_graph_tests | g2 | create_property_graph_tests.g2 (21 rows) +-- test object address functions with recursive dependency walk +-- covers all property graph object types including indirect dependents +SELECT * +FROM ( + WITH RECURSIVE deps (classid, objid, objsubid, refclassid, refobjid, refobjsubid) AS ( + SELECT classid, objid, objsubid, + refclassid, refobjid, refobjsubid + FROM pg_depend + WHERE refclassid = 'pg_class'::regclass AND + refobjid = 'create_property_graph_tests.gt'::regclass + UNION ALL + SELECT d.classid, d.objid, d.objsubid, + d.refclassid, d.refobjid, d.refobjsubid + FROM pg_depend d + JOIN deps dp ON d.refclassid = dp.classid AND d.refobjid = dp.objid AND d.refobjsubid = dp.objsubid + ) + SELECT pg_describe_object(classid, objid, objsubid) as obj, + pg_identify_object(classid, objid, objsubid) as ident, + pg_identify_object_as_address(classid, objid, objsubid) as addr + FROM deps +) s +ORDER BY obj COLLATE "C", ident::text COLLATE "C"; + obj | ident | addr +----------------------------------------------------------+----------------------------------------------------------------------------+---------------------------------------------------------------------------- + edge e of property graph gt | ("property graph element",,,"e of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,e}",{}) + edge e of property graph gt | ("property graph element",,,"e of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,e}",{}) + edge e of property graph gt | ("property graph element",,,"e of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of property graph gt | ("property graph label",,,"e of create_property_graph_tests.gt") | ("property graph label","{create_property_graph_tests,gt,e}",{}) + label v1 of property graph gt | ("property graph label",,,"v1 of create_property_graph_tests.gt") | ("property graph label","{create_property_graph_tests,gt,v1}",{}) + label v1 of vertex v1 of property graph gt | ("property graph element label",,,"v1 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v1}",{}) + label v1 of vertex v1 of property graph gt | ("property graph element label",,,"v1 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v1}",{}) + label v2 of property graph gt | ("property graph label",,,"v2 of create_property_graph_tests.gt") | ("property graph label","{create_property_graph_tests,gt,v2}",{}) + label v2 of vertex v2 of property graph gt | ("property graph element label",,,"v2 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v2}",{}) + label v2 of vertex v2 of property graph gt | ("property graph element label",,,"v2 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v2}",{}) + property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property a of property graph gt | ("property graph property",,,"a of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,a}",{}) + property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property b of property graph gt | ("property graph property",,,"b of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,b}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of property graph gt | ("property graph property",,,"c of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,c}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of property graph gt | ("property graph property",,,"k1 of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,k1}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of property graph gt | ("property graph property",,,"k2 of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,k2}",{}) + property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property m of property graph gt | ("property graph property",,,"m of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,m}",{}) + property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property n of property graph gt | ("property graph property",,,"n of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,n}",{}) + type gt | (type,create_property_graph_tests,gt,create_property_graph_tests.gt) | (type,{create_property_graph_tests.gt},{}) + type gt[] | (type,create_property_graph_tests,_gt,create_property_graph_tests.gt[]) | (type,{create_property_graph_tests.gt[]},{}) + vertex v1 of property graph gt | ("property graph element",,,"v1 of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,v1}",{}) + vertex v2 of property graph gt | ("property graph element",,,"v2 of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,v2}",{}) +(52 rows) + \a\t SELECT pg_get_propgraphdef('g2'::regclass); CREATE PROPERTY GRAPH create_property_graph_tests.g2 diff --git a/src/test/regress/expected/event_trigger.out b/src/test/regress/expected/event_trigger.out index 065f586310f..ed8d5df397e 100644 --- a/src/test/regress/expected/event_trigger.out +++ b/src/test/regress/expected/event_trigger.out @@ -173,6 +173,23 @@ NOTICE: test_event_trigger: ddl_command_end CREATE USER MAPPING alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; NOTICE: test_event_trigger: ddl_command_end ALTER DEFAULT PRIVILEGES +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE TABLE t2x (i int PRIMARY KEY, j text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); +NOTICE: test_event_trigger: ddl_command_end CREATE PROPERTY GRAPH +DROP PROPERTY GRAPH gx; +NOTICE: test_event_trigger: ddl_command_end DROP PROPERTY GRAPH +DROP TABLE t1x, t2x; +NOTICE: test_event_trigger: ddl_command_end DROP TABLE -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; ERROR: permission denied to change owner of event trigger "regress_event_trigger" diff --git a/src/test/regress/expected/object_address.out b/src/test/regress/expected/object_address.out index 97227d67a54..5e53f0b092e 100644 --- a/src/test/regress/expected/object_address.out +++ b/src/test/regress/expected/object_address.out @@ -67,7 +67,9 @@ DECLARE BEGIN FOR objtype IN VALUES ('toast table'), ('index column'), ('sequence column'), ('toast table column'), ('view column'), ('materialized view column'), - ('property graph element'), ('property graph label'), ('property graph property') + ('property graph element'), ('property graph element label'), + ('property graph label'), ('property graph label property'), + ('property graph property') LOOP BEGIN PERFORM pg_get_object_address(objtype, '{one}', '{}'); @@ -84,7 +86,9 @@ WARNING: error for toast table column: unsupported object type "toast table col WARNING: error for view column: unsupported object type "view column" WARNING: error for materialized view column: unsupported object type "materialized view column" WARNING: error for property graph element: unsupported object type "property graph element" +WARNING: error for property graph element label: unrecognized object type "property graph element label" WARNING: error for property graph label: unsupported object type "property graph label" +WARNING: error for property graph label property: unrecognized object type "property graph label property" WARNING: error for property graph property: unsupported object type "property graph property" -- miscellaneous other errors select * from pg_get_object_address('operator of access method', '{btree,integer_ops,1}', '{int4,bool}'); @@ -593,7 +597,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace @@ -653,6 +659,8 @@ ORDER BY objects.classid, objects.objid, objects.objsubid; ("(""parameter ACL"",,,)")|("(""parameter ACL"",,)")|NULL ("(""property graph element"",,,)")|("(""property graph element"",,)")|NULL ("(""property graph label"",,,)")|("(""property graph label"",,)")|NULL +("(""property graph element label"",,,)")|("(""property graph element label"",,)")|NULL ("(""property graph property"",,,)")|("(""property graph property"",,)")|NULL +("(""property graph label property"",,,)")|("(""property graph label property"",,)")|NULL -- restore normal output mode \a\t diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..9608dd5c4af 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -298,6 +298,29 @@ SELECT (pg_identify_object(classid, objid, objsubid)).* refobjid = 'create_property_graph_tests.g2'::regclass ORDER BY 1, 2, 3, 4; +-- test object address functions with recursive dependency walk +-- covers all property graph object types including indirect dependents +SELECT * +FROM ( + WITH RECURSIVE deps (classid, objid, objsubid, refclassid, refobjid, refobjsubid) AS ( + SELECT classid, objid, objsubid, + refclassid, refobjid, refobjsubid + FROM pg_depend + WHERE refclassid = 'pg_class'::regclass AND + refobjid = 'create_property_graph_tests.gt'::regclass + UNION ALL + SELECT d.classid, d.objid, d.objsubid, + d.refclassid, d.refobjid, d.refobjsubid + FROM pg_depend d + JOIN deps dp ON d.refclassid = dp.classid AND d.refobjid = dp.objid AND d.refobjsubid = dp.objsubid + ) + SELECT pg_describe_object(classid, objid, objsubid) as obj, + pg_identify_object(classid, objid, objsubid) as ident, + pg_identify_object_as_address(classid, objid, objsubid) as addr + FROM deps +) s +ORDER BY obj COLLATE "C", ident::text COLLATE "C"; + \a\t SELECT pg_get_propgraphdef('g2'::regclass); SELECT pg_get_propgraphdef('g3'::regclass); diff --git a/src/test/regress/sql/event_trigger.sql b/src/test/regress/sql/event_trigger.sql index 32e9bb58c5e..271f443378b 100644 --- a/src/test/regress/sql/event_trigger.sql +++ b/src/test/regress/sql/event_trigger.sql @@ -143,6 +143,19 @@ create user mapping for regress_evt_user server useless_server; alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +CREATE TABLE t2x (i int PRIMARY KEY, j text); + +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); + +DROP PROPERTY GRAPH gx; +DROP TABLE t1x, t2x; + -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; diff --git a/src/test/regress/sql/object_address.sql b/src/test/regress/sql/object_address.sql index 1bbe9457c1c..27109d421c7 100644 --- a/src/test/regress/sql/object_address.sql +++ b/src/test/regress/sql/object_address.sql @@ -67,7 +67,9 @@ DECLARE BEGIN FOR objtype IN VALUES ('toast table'), ('index column'), ('sequence column'), ('toast table column'), ('view column'), ('materialized view column'), - ('property graph element'), ('property graph label'), ('property graph property') + ('property graph element'), ('property graph element label'), + ('property graph label'), ('property graph label property'), + ('property graph property') LOOP BEGIN PERFORM pg_get_object_address(objtype, '{one}', '{}'); @@ -282,7 +284,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace -- 2.34.1 --R84XrR4Hgw0dH3Ec-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v2] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-23 09:27 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-23 09:27 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing them to hit the default case and error out with "unsupported object class". During DROP PROPERTY GRAPH, this manifests when an event trigger is active, because pg_event_trigger_ddl_commands() calls these functions. The same code paths are also reachable via pg_identify_object() and pg_identify_object_as_address(). This commit adds the missing cases. Test coverage is added in object_address.sql for these two catalog types via the zero-OID test that exercises pg_identify_object() and pg_identify_object_as_address(). A test in event_trigger.sql verifies that DROP PROPERTY GRAPH works correctly when an event trigger is active. Author: Bertrand Drouvot <[email protected]> Reviewed-by: Michael Paquier <[email protected]> Reviewed-by: Ashutosh Bapat <[email protected]> Discussion: https://postgr.es/m/aej1DkLwhyZWmtxJ@bdtpg --- src/backend/catalog/objectaddress.c | 93 ++++++++++++++++++++ src/test/regress/expected/event_trigger.out | 17 ++++ src/test/regress/expected/object_address.out | 4 + src/test/regress/sql/event_trigger.sql | 13 +++ src/test/regress/sql/object_address.sql | 2 + 5 files changed, 129 insertions(+) 62.4% src/backend/catalog/ 25.6% src/test/regress/expected/ 11.8% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/event_trigger.out b/src/test/regress/expected/event_trigger.out index 065f586310f..ed8d5df397e 100644 --- a/src/test/regress/expected/event_trigger.out +++ b/src/test/regress/expected/event_trigger.out @@ -173,6 +173,23 @@ NOTICE: test_event_trigger: ddl_command_end CREATE USER MAPPING alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; NOTICE: test_event_trigger: ddl_command_end ALTER DEFAULT PRIVILEGES +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE TABLE t2x (i int PRIMARY KEY, j text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); +NOTICE: test_event_trigger: ddl_command_end CREATE PROPERTY GRAPH +DROP PROPERTY GRAPH gx; +NOTICE: test_event_trigger: ddl_command_end DROP PROPERTY GRAPH +DROP TABLE t1x, t2x; +NOTICE: test_event_trigger: ddl_command_end DROP TABLE -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; ERROR: permission denied to change owner of event trigger "regress_event_trigger" diff --git a/src/test/regress/expected/object_address.out b/src/test/regress/expected/object_address.out index 97227d67a54..729c3537f25 100644 --- a/src/test/regress/expected/object_address.out +++ b/src/test/regress/expected/object_address.out @@ -593,7 +593,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace @@ -653,6 +655,8 @@ ORDER BY objects.classid, objects.objid, objects.objsubid; ("(""parameter ACL"",,,)")|("(""parameter ACL"",,)")|NULL ("(""property graph element"",,,)")|("(""property graph element"",,)")|NULL ("(""property graph label"",,,)")|("(""property graph label"",,)")|NULL +("(""property graph element label"",,,)")|("(""property graph element label"",,)")|NULL ("(""property graph property"",,,)")|("(""property graph property"",,)")|NULL +("(""property graph label property"",,,)")|("(""property graph label property"",,)")|NULL -- restore normal output mode \a\t diff --git a/src/test/regress/sql/event_trigger.sql b/src/test/regress/sql/event_trigger.sql index 32e9bb58c5e..271f443378b 100644 --- a/src/test/regress/sql/event_trigger.sql +++ b/src/test/regress/sql/event_trigger.sql @@ -143,6 +143,19 @@ create user mapping for regress_evt_user server useless_server; alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +CREATE TABLE t2x (i int PRIMARY KEY, j text); + +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); + +DROP PROPERTY GRAPH gx; +DROP TABLE t1x, t2x; + -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; diff --git a/src/test/regress/sql/object_address.sql b/src/test/regress/sql/object_address.sql index 1bbe9457c1c..620dacf1045 100644 --- a/src/test/regress/sql/object_address.sql +++ b/src/test/regress/sql/object_address.sql @@ -282,7 +282,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace -- 2.34.1 --gtUR827Uq8d5gVsQ-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v2] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-23 09:27 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-23 09:27 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing them to hit the default case and error out with "unsupported object class". During DROP PROPERTY GRAPH, this manifests when an event trigger is active, because pg_event_trigger_ddl_commands() calls these functions. The same code paths are also reachable via pg_identify_object() and pg_identify_object_as_address(). This commit adds the missing cases. Test coverage is added in object_address.sql for these two catalog types via the zero-OID test that exercises pg_identify_object() and pg_identify_object_as_address(). A test in event_trigger.sql verifies that DROP PROPERTY GRAPH works correctly when an event trigger is active. Author: Bertrand Drouvot <[email protected]> Reviewed-by: Michael Paquier <[email protected]> Reviewed-by: Ashutosh Bapat <[email protected]> Discussion: https://postgr.es/m/aej1DkLwhyZWmtxJ@bdtpg --- src/backend/catalog/objectaddress.c | 93 ++++++++++++++++++++ src/test/regress/expected/event_trigger.out | 17 ++++ src/test/regress/expected/object_address.out | 4 + src/test/regress/sql/event_trigger.sql | 13 +++ src/test/regress/sql/object_address.sql | 2 + 5 files changed, 129 insertions(+) 62.4% src/backend/catalog/ 25.6% src/test/regress/expected/ 11.8% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/event_trigger.out b/src/test/regress/expected/event_trigger.out index 065f586310f..ed8d5df397e 100644 --- a/src/test/regress/expected/event_trigger.out +++ b/src/test/regress/expected/event_trigger.out @@ -173,6 +173,23 @@ NOTICE: test_event_trigger: ddl_command_end CREATE USER MAPPING alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; NOTICE: test_event_trigger: ddl_command_end ALTER DEFAULT PRIVILEGES +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE TABLE t2x (i int PRIMARY KEY, j text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); +NOTICE: test_event_trigger: ddl_command_end CREATE PROPERTY GRAPH +DROP PROPERTY GRAPH gx; +NOTICE: test_event_trigger: ddl_command_end DROP PROPERTY GRAPH +DROP TABLE t1x, t2x; +NOTICE: test_event_trigger: ddl_command_end DROP TABLE -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; ERROR: permission denied to change owner of event trigger "regress_event_trigger" diff --git a/src/test/regress/expected/object_address.out b/src/test/regress/expected/object_address.out index 97227d67a54..729c3537f25 100644 --- a/src/test/regress/expected/object_address.out +++ b/src/test/regress/expected/object_address.out @@ -593,7 +593,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace @@ -653,6 +655,8 @@ ORDER BY objects.classid, objects.objid, objects.objsubid; ("(""parameter ACL"",,,)")|("(""parameter ACL"",,)")|NULL ("(""property graph element"",,,)")|("(""property graph element"",,)")|NULL ("(""property graph label"",,,)")|("(""property graph label"",,)")|NULL +("(""property graph element label"",,,)")|("(""property graph element label"",,)")|NULL ("(""property graph property"",,,)")|("(""property graph property"",,)")|NULL +("(""property graph label property"",,,)")|("(""property graph label property"",,)")|NULL -- restore normal output mode \a\t diff --git a/src/test/regress/sql/event_trigger.sql b/src/test/regress/sql/event_trigger.sql index 32e9bb58c5e..271f443378b 100644 --- a/src/test/regress/sql/event_trigger.sql +++ b/src/test/regress/sql/event_trigger.sql @@ -143,6 +143,19 @@ create user mapping for regress_evt_user server useless_server; alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +CREATE TABLE t2x (i int PRIMARY KEY, j text); + +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); + +DROP PROPERTY GRAPH gx; +DROP TABLE t1x, t2x; + -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; diff --git a/src/test/regress/sql/object_address.sql b/src/test/regress/sql/object_address.sql index 1bbe9457c1c..620dacf1045 100644 --- a/src/test/regress/sql/object_address.sql +++ b/src/test/regress/sql/object_address.sql @@ -282,7 +282,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace -- 2.34.1 --gtUR827Uq8d5gVsQ-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v2] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-23 09:27 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-23 09:27 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing them to hit the default case and error out with "unsupported object class". During DROP PROPERTY GRAPH, this manifests when an event trigger is active, because pg_event_trigger_ddl_commands() calls these functions. The same code paths are also reachable via pg_identify_object() and pg_identify_object_as_address(). This commit adds the missing cases. Test coverage is added in object_address.sql for these two catalog types via the zero-OID test that exercises pg_identify_object() and pg_identify_object_as_address(). A test in event_trigger.sql verifies that DROP PROPERTY GRAPH works correctly when an event trigger is active. Author: Bertrand Drouvot <[email protected]> Reviewed-by: Michael Paquier <[email protected]> Reviewed-by: Ashutosh Bapat <[email protected]> Discussion: https://postgr.es/m/aej1DkLwhyZWmtxJ@bdtpg --- src/backend/catalog/objectaddress.c | 93 ++++++++++++++++++++ src/test/regress/expected/event_trigger.out | 17 ++++ src/test/regress/expected/object_address.out | 4 + src/test/regress/sql/event_trigger.sql | 13 +++ src/test/regress/sql/object_address.sql | 2 + 5 files changed, 129 insertions(+) 62.4% src/backend/catalog/ 25.6% src/test/regress/expected/ 11.8% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/event_trigger.out b/src/test/regress/expected/event_trigger.out index 065f586310f..ed8d5df397e 100644 --- a/src/test/regress/expected/event_trigger.out +++ b/src/test/regress/expected/event_trigger.out @@ -173,6 +173,23 @@ NOTICE: test_event_trigger: ddl_command_end CREATE USER MAPPING alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; NOTICE: test_event_trigger: ddl_command_end ALTER DEFAULT PRIVILEGES +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE TABLE t2x (i int PRIMARY KEY, j text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); +NOTICE: test_event_trigger: ddl_command_end CREATE PROPERTY GRAPH +DROP PROPERTY GRAPH gx; +NOTICE: test_event_trigger: ddl_command_end DROP PROPERTY GRAPH +DROP TABLE t1x, t2x; +NOTICE: test_event_trigger: ddl_command_end DROP TABLE -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; ERROR: permission denied to change owner of event trigger "regress_event_trigger" diff --git a/src/test/regress/expected/object_address.out b/src/test/regress/expected/object_address.out index 97227d67a54..729c3537f25 100644 --- a/src/test/regress/expected/object_address.out +++ b/src/test/regress/expected/object_address.out @@ -593,7 +593,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace @@ -653,6 +655,8 @@ ORDER BY objects.classid, objects.objid, objects.objsubid; ("(""parameter ACL"",,,)")|("(""parameter ACL"",,)")|NULL ("(""property graph element"",,,)")|("(""property graph element"",,)")|NULL ("(""property graph label"",,,)")|("(""property graph label"",,)")|NULL +("(""property graph element label"",,,)")|("(""property graph element label"",,)")|NULL ("(""property graph property"",,,)")|("(""property graph property"",,)")|NULL +("(""property graph label property"",,,)")|("(""property graph label property"",,)")|NULL -- restore normal output mode \a\t diff --git a/src/test/regress/sql/event_trigger.sql b/src/test/regress/sql/event_trigger.sql index 32e9bb58c5e..271f443378b 100644 --- a/src/test/regress/sql/event_trigger.sql +++ b/src/test/regress/sql/event_trigger.sql @@ -143,6 +143,19 @@ create user mapping for regress_evt_user server useless_server; alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +CREATE TABLE t2x (i int PRIMARY KEY, j text); + +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); + +DROP PROPERTY GRAPH gx; +DROP TABLE t1x, t2x; + -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; diff --git a/src/test/regress/sql/object_address.sql b/src/test/regress/sql/object_address.sql index 1bbe9457c1c..620dacf1045 100644 --- a/src/test/regress/sql/object_address.sql +++ b/src/test/regress/sql/object_address.sql @@ -282,7 +282,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace -- 2.34.1 --gtUR827Uq8d5gVsQ-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v3] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-23 09:27 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-23 09:27 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing them to hit the default case and error out with "unsupported object class". During DROP PROPERTY GRAPH, this manifests when an event trigger is active, because pg_event_trigger_ddl_commands() calls these functions. The same code paths are also reachable via pg_identify_object() and pg_identify_object_as_address(). This commit adds the missing cases. Test coverage is added in object_address.sql for these two catalog types and in create_property_graph.sql covering all property graph object types. A test in event_trigger.sql verifies that DROP PROPERTY GRAPH works correctly when an event trigger is active. Author: Bertrand Drouvot <[email protected]> Reviewed-by: Michael Paquier <[email protected]> Reviewed-by: Ashutosh Bapat <[email protected]> Discussion: https://postgr.es/m/aej1DkLwhyZWmtxJ@bdtpg --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 78 ++++++++++++++++ src/test/regress/expected/event_trigger.out | 17 ++++ src/test/regress/expected/object_address.out | 10 +- .../regress/sql/create_property_graph.sql | 23 +++++ src/test/regress/sql/event_trigger.sql | 13 +++ src/test/regress/sql/object_address.sql | 6 +- 7 files changed, 238 insertions(+), 2 deletions(-) 14.7% src/backend/catalog/ 75.5% src/test/regress/expected/ 9.7% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..eb9e17fb727 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -752,6 +752,84 @@ SELECT (pg_identify_object(classid, objid, objsubid)).* type | create_property_graph_tests | g2 | create_property_graph_tests.g2 (21 rows) +-- test object address functions with recursive dependency walk +-- covers all property graph object types including indirect dependents +SELECT * +FROM ( + WITH RECURSIVE deps (classid, objid, objsubid, refclassid, refobjid, refobjsubid) AS ( + SELECT classid, objid, objsubid, + refclassid, refobjid, refobjsubid + FROM pg_depend + WHERE refclassid = 'pg_class'::regclass AND + refobjid = 'create_property_graph_tests.gt'::regclass + UNION ALL + SELECT d.classid, d.objid, d.objsubid, + d.refclassid, d.refobjid, d.refobjsubid + FROM pg_depend d + JOIN deps dp ON d.refclassid = dp.classid AND d.refobjid = dp.objid AND d.refobjsubid = dp.objsubid + ) + SELECT pg_describe_object(classid, objid, objsubid) as obj, + pg_identify_object(classid, objid, objsubid) as ident, + pg_identify_object_as_address(classid, objid, objsubid) as addr + FROM deps +) s +ORDER BY obj COLLATE "C", ident::text COLLATE "C"; + obj | ident | addr +----------------------------------------------------------+----------------------------------------------------------------------------+---------------------------------------------------------------------------- + edge e of property graph gt | ("property graph element",,,"e of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,e}",{}) + edge e of property graph gt | ("property graph element",,,"e of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,e}",{}) + edge e of property graph gt | ("property graph element",,,"e of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of property graph gt | ("property graph label",,,"e of create_property_graph_tests.gt") | ("property graph label","{create_property_graph_tests,gt,e}",{}) + label v1 of property graph gt | ("property graph label",,,"v1 of create_property_graph_tests.gt") | ("property graph label","{create_property_graph_tests,gt,v1}",{}) + label v1 of vertex v1 of property graph gt | ("property graph element label",,,"v1 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v1}",{}) + label v1 of vertex v1 of property graph gt | ("property graph element label",,,"v1 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v1}",{}) + label v2 of property graph gt | ("property graph label",,,"v2 of create_property_graph_tests.gt") | ("property graph label","{create_property_graph_tests,gt,v2}",{}) + label v2 of vertex v2 of property graph gt | ("property graph element label",,,"v2 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v2}",{}) + label v2 of vertex v2 of property graph gt | ("property graph element label",,,"v2 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v2}",{}) + property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property a of property graph gt | ("property graph property",,,"a of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,a}",{}) + property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property b of property graph gt | ("property graph property",,,"b of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,b}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of property graph gt | ("property graph property",,,"c of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,c}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of property graph gt | ("property graph property",,,"k1 of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,k1}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of property graph gt | ("property graph property",,,"k2 of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,k2}",{}) + property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property m of property graph gt | ("property graph property",,,"m of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,m}",{}) + property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property n of property graph gt | ("property graph property",,,"n of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,n}",{}) + type gt | (type,create_property_graph_tests,gt,create_property_graph_tests.gt) | (type,{create_property_graph_tests.gt},{}) + type gt[] | (type,create_property_graph_tests,_gt,create_property_graph_tests.gt[]) | (type,{create_property_graph_tests.gt[]},{}) + vertex v1 of property graph gt | ("property graph element",,,"v1 of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,v1}",{}) + vertex v2 of property graph gt | ("property graph element",,,"v2 of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,v2}",{}) +(52 rows) + \a\t SELECT pg_get_propgraphdef('g2'::regclass); CREATE PROPERTY GRAPH create_property_graph_tests.g2 diff --git a/src/test/regress/expected/event_trigger.out b/src/test/regress/expected/event_trigger.out index 065f586310f..ed8d5df397e 100644 --- a/src/test/regress/expected/event_trigger.out +++ b/src/test/regress/expected/event_trigger.out @@ -173,6 +173,23 @@ NOTICE: test_event_trigger: ddl_command_end CREATE USER MAPPING alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; NOTICE: test_event_trigger: ddl_command_end ALTER DEFAULT PRIVILEGES +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE TABLE t2x (i int PRIMARY KEY, j text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); +NOTICE: test_event_trigger: ddl_command_end CREATE PROPERTY GRAPH +DROP PROPERTY GRAPH gx; +NOTICE: test_event_trigger: ddl_command_end DROP PROPERTY GRAPH +DROP TABLE t1x, t2x; +NOTICE: test_event_trigger: ddl_command_end DROP TABLE -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; ERROR: permission denied to change owner of event trigger "regress_event_trigger" diff --git a/src/test/regress/expected/object_address.out b/src/test/regress/expected/object_address.out index 97227d67a54..5e53f0b092e 100644 --- a/src/test/regress/expected/object_address.out +++ b/src/test/regress/expected/object_address.out @@ -67,7 +67,9 @@ DECLARE BEGIN FOR objtype IN VALUES ('toast table'), ('index column'), ('sequence column'), ('toast table column'), ('view column'), ('materialized view column'), - ('property graph element'), ('property graph label'), ('property graph property') + ('property graph element'), ('property graph element label'), + ('property graph label'), ('property graph label property'), + ('property graph property') LOOP BEGIN PERFORM pg_get_object_address(objtype, '{one}', '{}'); @@ -84,7 +86,9 @@ WARNING: error for toast table column: unsupported object type "toast table col WARNING: error for view column: unsupported object type "view column" WARNING: error for materialized view column: unsupported object type "materialized view column" WARNING: error for property graph element: unsupported object type "property graph element" +WARNING: error for property graph element label: unrecognized object type "property graph element label" WARNING: error for property graph label: unsupported object type "property graph label" +WARNING: error for property graph label property: unrecognized object type "property graph label property" WARNING: error for property graph property: unsupported object type "property graph property" -- miscellaneous other errors select * from pg_get_object_address('operator of access method', '{btree,integer_ops,1}', '{int4,bool}'); @@ -593,7 +597,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace @@ -653,6 +659,8 @@ ORDER BY objects.classid, objects.objid, objects.objsubid; ("(""parameter ACL"",,,)")|("(""parameter ACL"",,)")|NULL ("(""property graph element"",,,)")|("(""property graph element"",,)")|NULL ("(""property graph label"",,,)")|("(""property graph label"",,)")|NULL +("(""property graph element label"",,,)")|("(""property graph element label"",,)")|NULL ("(""property graph property"",,,)")|("(""property graph property"",,)")|NULL +("(""property graph label property"",,,)")|("(""property graph label property"",,)")|NULL -- restore normal output mode \a\t diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..9608dd5c4af 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -298,6 +298,29 @@ SELECT (pg_identify_object(classid, objid, objsubid)).* refobjid = 'create_property_graph_tests.g2'::regclass ORDER BY 1, 2, 3, 4; +-- test object address functions with recursive dependency walk +-- covers all property graph object types including indirect dependents +SELECT * +FROM ( + WITH RECURSIVE deps (classid, objid, objsubid, refclassid, refobjid, refobjsubid) AS ( + SELECT classid, objid, objsubid, + refclassid, refobjid, refobjsubid + FROM pg_depend + WHERE refclassid = 'pg_class'::regclass AND + refobjid = 'create_property_graph_tests.gt'::regclass + UNION ALL + SELECT d.classid, d.objid, d.objsubid, + d.refclassid, d.refobjid, d.refobjsubid + FROM pg_depend d + JOIN deps dp ON d.refclassid = dp.classid AND d.refobjid = dp.objid AND d.refobjsubid = dp.objsubid + ) + SELECT pg_describe_object(classid, objid, objsubid) as obj, + pg_identify_object(classid, objid, objsubid) as ident, + pg_identify_object_as_address(classid, objid, objsubid) as addr + FROM deps +) s +ORDER BY obj COLLATE "C", ident::text COLLATE "C"; + \a\t SELECT pg_get_propgraphdef('g2'::regclass); SELECT pg_get_propgraphdef('g3'::regclass); diff --git a/src/test/regress/sql/event_trigger.sql b/src/test/regress/sql/event_trigger.sql index 32e9bb58c5e..271f443378b 100644 --- a/src/test/regress/sql/event_trigger.sql +++ b/src/test/regress/sql/event_trigger.sql @@ -143,6 +143,19 @@ create user mapping for regress_evt_user server useless_server; alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +CREATE TABLE t2x (i int PRIMARY KEY, j text); + +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); + +DROP PROPERTY GRAPH gx; +DROP TABLE t1x, t2x; + -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; diff --git a/src/test/regress/sql/object_address.sql b/src/test/regress/sql/object_address.sql index 1bbe9457c1c..27109d421c7 100644 --- a/src/test/regress/sql/object_address.sql +++ b/src/test/regress/sql/object_address.sql @@ -67,7 +67,9 @@ DECLARE BEGIN FOR objtype IN VALUES ('toast table'), ('index column'), ('sequence column'), ('toast table column'), ('view column'), ('materialized view column'), - ('property graph element'), ('property graph label'), ('property graph property') + ('property graph element'), ('property graph element label'), + ('property graph label'), ('property graph label property'), + ('property graph property') LOOP BEGIN PERFORM pg_get_object_address(objtype, '{one}', '{}'); @@ -282,7 +284,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace -- 2.34.1 --R84XrR4Hgw0dH3Ec-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v2] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-23 09:27 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-23 09:27 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing them to hit the default case and error out with "unsupported object class". During DROP PROPERTY GRAPH, this manifests when an event trigger is active, because pg_event_trigger_ddl_commands() calls these functions. The same code paths are also reachable via pg_identify_object() and pg_identify_object_as_address(). This commit adds the missing cases. Test coverage is added in object_address.sql for these two catalog types via the zero-OID test that exercises pg_identify_object() and pg_identify_object_as_address(). A test in event_trigger.sql verifies that DROP PROPERTY GRAPH works correctly when an event trigger is active. Author: Bertrand Drouvot <[email protected]> Reviewed-by: Michael Paquier <[email protected]> Reviewed-by: Ashutosh Bapat <[email protected]> Discussion: https://postgr.es/m/aej1DkLwhyZWmtxJ@bdtpg --- src/backend/catalog/objectaddress.c | 93 ++++++++++++++++++++ src/test/regress/expected/event_trigger.out | 17 ++++ src/test/regress/expected/object_address.out | 4 + src/test/regress/sql/event_trigger.sql | 13 +++ src/test/regress/sql/object_address.sql | 2 + 5 files changed, 129 insertions(+) 62.4% src/backend/catalog/ 25.6% src/test/regress/expected/ 11.8% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/event_trigger.out b/src/test/regress/expected/event_trigger.out index 065f586310f..ed8d5df397e 100644 --- a/src/test/regress/expected/event_trigger.out +++ b/src/test/regress/expected/event_trigger.out @@ -173,6 +173,23 @@ NOTICE: test_event_trigger: ddl_command_end CREATE USER MAPPING alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; NOTICE: test_event_trigger: ddl_command_end ALTER DEFAULT PRIVILEGES +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE TABLE t2x (i int PRIMARY KEY, j text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); +NOTICE: test_event_trigger: ddl_command_end CREATE PROPERTY GRAPH +DROP PROPERTY GRAPH gx; +NOTICE: test_event_trigger: ddl_command_end DROP PROPERTY GRAPH +DROP TABLE t1x, t2x; +NOTICE: test_event_trigger: ddl_command_end DROP TABLE -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; ERROR: permission denied to change owner of event trigger "regress_event_trigger" diff --git a/src/test/regress/expected/object_address.out b/src/test/regress/expected/object_address.out index 97227d67a54..729c3537f25 100644 --- a/src/test/regress/expected/object_address.out +++ b/src/test/regress/expected/object_address.out @@ -593,7 +593,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace @@ -653,6 +655,8 @@ ORDER BY objects.classid, objects.objid, objects.objsubid; ("(""parameter ACL"",,,)")|("(""parameter ACL"",,)")|NULL ("(""property graph element"",,,)")|("(""property graph element"",,)")|NULL ("(""property graph label"",,,)")|("(""property graph label"",,)")|NULL +("(""property graph element label"",,,)")|("(""property graph element label"",,)")|NULL ("(""property graph property"",,,)")|("(""property graph property"",,)")|NULL +("(""property graph label property"",,,)")|("(""property graph label property"",,)")|NULL -- restore normal output mode \a\t diff --git a/src/test/regress/sql/event_trigger.sql b/src/test/regress/sql/event_trigger.sql index 32e9bb58c5e..271f443378b 100644 --- a/src/test/regress/sql/event_trigger.sql +++ b/src/test/regress/sql/event_trigger.sql @@ -143,6 +143,19 @@ create user mapping for regress_evt_user server useless_server; alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +CREATE TABLE t2x (i int PRIMARY KEY, j text); + +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); + +DROP PROPERTY GRAPH gx; +DROP TABLE t1x, t2x; + -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; diff --git a/src/test/regress/sql/object_address.sql b/src/test/regress/sql/object_address.sql index 1bbe9457c1c..620dacf1045 100644 --- a/src/test/regress/sql/object_address.sql +++ b/src/test/regress/sql/object_address.sql @@ -282,7 +282,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace -- 2.34.1 --gtUR827Uq8d5gVsQ-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v2] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-23 09:27 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-23 09:27 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing them to hit the default case and error out with "unsupported object class". During DROP PROPERTY GRAPH, this manifests when an event trigger is active, because pg_event_trigger_ddl_commands() calls these functions. The same code paths are also reachable via pg_identify_object() and pg_identify_object_as_address(). This commit adds the missing cases. Test coverage is added in object_address.sql for these two catalog types via the zero-OID test that exercises pg_identify_object() and pg_identify_object_as_address(). A test in event_trigger.sql verifies that DROP PROPERTY GRAPH works correctly when an event trigger is active. Author: Bertrand Drouvot <[email protected]> Reviewed-by: Michael Paquier <[email protected]> Reviewed-by: Ashutosh Bapat <[email protected]> Discussion: https://postgr.es/m/aej1DkLwhyZWmtxJ@bdtpg --- src/backend/catalog/objectaddress.c | 93 ++++++++++++++++++++ src/test/regress/expected/event_trigger.out | 17 ++++ src/test/regress/expected/object_address.out | 4 + src/test/regress/sql/event_trigger.sql | 13 +++ src/test/regress/sql/object_address.sql | 2 + 5 files changed, 129 insertions(+) 62.4% src/backend/catalog/ 25.6% src/test/regress/expected/ 11.8% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/event_trigger.out b/src/test/regress/expected/event_trigger.out index 065f586310f..ed8d5df397e 100644 --- a/src/test/regress/expected/event_trigger.out +++ b/src/test/regress/expected/event_trigger.out @@ -173,6 +173,23 @@ NOTICE: test_event_trigger: ddl_command_end CREATE USER MAPPING alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; NOTICE: test_event_trigger: ddl_command_end ALTER DEFAULT PRIVILEGES +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE TABLE t2x (i int PRIMARY KEY, j text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); +NOTICE: test_event_trigger: ddl_command_end CREATE PROPERTY GRAPH +DROP PROPERTY GRAPH gx; +NOTICE: test_event_trigger: ddl_command_end DROP PROPERTY GRAPH +DROP TABLE t1x, t2x; +NOTICE: test_event_trigger: ddl_command_end DROP TABLE -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; ERROR: permission denied to change owner of event trigger "regress_event_trigger" diff --git a/src/test/regress/expected/object_address.out b/src/test/regress/expected/object_address.out index 97227d67a54..729c3537f25 100644 --- a/src/test/regress/expected/object_address.out +++ b/src/test/regress/expected/object_address.out @@ -593,7 +593,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace @@ -653,6 +655,8 @@ ORDER BY objects.classid, objects.objid, objects.objsubid; ("(""parameter ACL"",,,)")|("(""parameter ACL"",,)")|NULL ("(""property graph element"",,,)")|("(""property graph element"",,)")|NULL ("(""property graph label"",,,)")|("(""property graph label"",,)")|NULL +("(""property graph element label"",,,)")|("(""property graph element label"",,)")|NULL ("(""property graph property"",,,)")|("(""property graph property"",,)")|NULL +("(""property graph label property"",,,)")|("(""property graph label property"",,)")|NULL -- restore normal output mode \a\t diff --git a/src/test/regress/sql/event_trigger.sql b/src/test/regress/sql/event_trigger.sql index 32e9bb58c5e..271f443378b 100644 --- a/src/test/regress/sql/event_trigger.sql +++ b/src/test/regress/sql/event_trigger.sql @@ -143,6 +143,19 @@ create user mapping for regress_evt_user server useless_server; alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +CREATE TABLE t2x (i int PRIMARY KEY, j text); + +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); + +DROP PROPERTY GRAPH gx; +DROP TABLE t1x, t2x; + -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; diff --git a/src/test/regress/sql/object_address.sql b/src/test/regress/sql/object_address.sql index 1bbe9457c1c..620dacf1045 100644 --- a/src/test/regress/sql/object_address.sql +++ b/src/test/regress/sql/object_address.sql @@ -282,7 +282,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace -- 2.34.1 --gtUR827Uq8d5gVsQ-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v3] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-23 09:27 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-23 09:27 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing them to hit the default case and error out with "unsupported object class". During DROP PROPERTY GRAPH, this manifests when an event trigger is active, because pg_event_trigger_ddl_commands() calls these functions. The same code paths are also reachable via pg_identify_object() and pg_identify_object_as_address(). This commit adds the missing cases. Test coverage is added in object_address.sql for these two catalog types and in create_property_graph.sql covering all property graph object types. A test in event_trigger.sql verifies that DROP PROPERTY GRAPH works correctly when an event trigger is active. Author: Bertrand Drouvot <[email protected]> Reviewed-by: Michael Paquier <[email protected]> Reviewed-by: Ashutosh Bapat <[email protected]> Discussion: https://postgr.es/m/aej1DkLwhyZWmtxJ@bdtpg --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 78 ++++++++++++++++ src/test/regress/expected/event_trigger.out | 17 ++++ src/test/regress/expected/object_address.out | 10 +- .../regress/sql/create_property_graph.sql | 23 +++++ src/test/regress/sql/event_trigger.sql | 13 +++ src/test/regress/sql/object_address.sql | 6 +- 7 files changed, 238 insertions(+), 2 deletions(-) 14.7% src/backend/catalog/ 75.5% src/test/regress/expected/ 9.7% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..eb9e17fb727 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -752,6 +752,84 @@ SELECT (pg_identify_object(classid, objid, objsubid)).* type | create_property_graph_tests | g2 | create_property_graph_tests.g2 (21 rows) +-- test object address functions with recursive dependency walk +-- covers all property graph object types including indirect dependents +SELECT * +FROM ( + WITH RECURSIVE deps (classid, objid, objsubid, refclassid, refobjid, refobjsubid) AS ( + SELECT classid, objid, objsubid, + refclassid, refobjid, refobjsubid + FROM pg_depend + WHERE refclassid = 'pg_class'::regclass AND + refobjid = 'create_property_graph_tests.gt'::regclass + UNION ALL + SELECT d.classid, d.objid, d.objsubid, + d.refclassid, d.refobjid, d.refobjsubid + FROM pg_depend d + JOIN deps dp ON d.refclassid = dp.classid AND d.refobjid = dp.objid AND d.refobjsubid = dp.objsubid + ) + SELECT pg_describe_object(classid, objid, objsubid) as obj, + pg_identify_object(classid, objid, objsubid) as ident, + pg_identify_object_as_address(classid, objid, objsubid) as addr + FROM deps +) s +ORDER BY obj COLLATE "C", ident::text COLLATE "C"; + obj | ident | addr +----------------------------------------------------------+----------------------------------------------------------------------------+---------------------------------------------------------------------------- + edge e of property graph gt | ("property graph element",,,"e of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,e}",{}) + edge e of property graph gt | ("property graph element",,,"e of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,e}",{}) + edge e of property graph gt | ("property graph element",,,"e of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of property graph gt | ("property graph label",,,"e of create_property_graph_tests.gt") | ("property graph label","{create_property_graph_tests,gt,e}",{}) + label v1 of property graph gt | ("property graph label",,,"v1 of create_property_graph_tests.gt") | ("property graph label","{create_property_graph_tests,gt,v1}",{}) + label v1 of vertex v1 of property graph gt | ("property graph element label",,,"v1 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v1}",{}) + label v1 of vertex v1 of property graph gt | ("property graph element label",,,"v1 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v1}",{}) + label v2 of property graph gt | ("property graph label",,,"v2 of create_property_graph_tests.gt") | ("property graph label","{create_property_graph_tests,gt,v2}",{}) + label v2 of vertex v2 of property graph gt | ("property graph element label",,,"v2 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v2}",{}) + label v2 of vertex v2 of property graph gt | ("property graph element label",,,"v2 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v2}",{}) + property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property a of property graph gt | ("property graph property",,,"a of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,a}",{}) + property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property b of property graph gt | ("property graph property",,,"b of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,b}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of property graph gt | ("property graph property",,,"c of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,c}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of property graph gt | ("property graph property",,,"k1 of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,k1}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of property graph gt | ("property graph property",,,"k2 of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,k2}",{}) + property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property m of property graph gt | ("property graph property",,,"m of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,m}",{}) + property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property n of property graph gt | ("property graph property",,,"n of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,n}",{}) + type gt | (type,create_property_graph_tests,gt,create_property_graph_tests.gt) | (type,{create_property_graph_tests.gt},{}) + type gt[] | (type,create_property_graph_tests,_gt,create_property_graph_tests.gt[]) | (type,{create_property_graph_tests.gt[]},{}) + vertex v1 of property graph gt | ("property graph element",,,"v1 of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,v1}",{}) + vertex v2 of property graph gt | ("property graph element",,,"v2 of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,v2}",{}) +(52 rows) + \a\t SELECT pg_get_propgraphdef('g2'::regclass); CREATE PROPERTY GRAPH create_property_graph_tests.g2 diff --git a/src/test/regress/expected/event_trigger.out b/src/test/regress/expected/event_trigger.out index 065f586310f..ed8d5df397e 100644 --- a/src/test/regress/expected/event_trigger.out +++ b/src/test/regress/expected/event_trigger.out @@ -173,6 +173,23 @@ NOTICE: test_event_trigger: ddl_command_end CREATE USER MAPPING alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; NOTICE: test_event_trigger: ddl_command_end ALTER DEFAULT PRIVILEGES +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE TABLE t2x (i int PRIMARY KEY, j text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); +NOTICE: test_event_trigger: ddl_command_end CREATE PROPERTY GRAPH +DROP PROPERTY GRAPH gx; +NOTICE: test_event_trigger: ddl_command_end DROP PROPERTY GRAPH +DROP TABLE t1x, t2x; +NOTICE: test_event_trigger: ddl_command_end DROP TABLE -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; ERROR: permission denied to change owner of event trigger "regress_event_trigger" diff --git a/src/test/regress/expected/object_address.out b/src/test/regress/expected/object_address.out index 97227d67a54..5e53f0b092e 100644 --- a/src/test/regress/expected/object_address.out +++ b/src/test/regress/expected/object_address.out @@ -67,7 +67,9 @@ DECLARE BEGIN FOR objtype IN VALUES ('toast table'), ('index column'), ('sequence column'), ('toast table column'), ('view column'), ('materialized view column'), - ('property graph element'), ('property graph label'), ('property graph property') + ('property graph element'), ('property graph element label'), + ('property graph label'), ('property graph label property'), + ('property graph property') LOOP BEGIN PERFORM pg_get_object_address(objtype, '{one}', '{}'); @@ -84,7 +86,9 @@ WARNING: error for toast table column: unsupported object type "toast table col WARNING: error for view column: unsupported object type "view column" WARNING: error for materialized view column: unsupported object type "materialized view column" WARNING: error for property graph element: unsupported object type "property graph element" +WARNING: error for property graph element label: unrecognized object type "property graph element label" WARNING: error for property graph label: unsupported object type "property graph label" +WARNING: error for property graph label property: unrecognized object type "property graph label property" WARNING: error for property graph property: unsupported object type "property graph property" -- miscellaneous other errors select * from pg_get_object_address('operator of access method', '{btree,integer_ops,1}', '{int4,bool}'); @@ -593,7 +597,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace @@ -653,6 +659,8 @@ ORDER BY objects.classid, objects.objid, objects.objsubid; ("(""parameter ACL"",,,)")|("(""parameter ACL"",,)")|NULL ("(""property graph element"",,,)")|("(""property graph element"",,)")|NULL ("(""property graph label"",,,)")|("(""property graph label"",,)")|NULL +("(""property graph element label"",,,)")|("(""property graph element label"",,)")|NULL ("(""property graph property"",,,)")|("(""property graph property"",,)")|NULL +("(""property graph label property"",,,)")|("(""property graph label property"",,)")|NULL -- restore normal output mode \a\t diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..9608dd5c4af 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -298,6 +298,29 @@ SELECT (pg_identify_object(classid, objid, objsubid)).* refobjid = 'create_property_graph_tests.g2'::regclass ORDER BY 1, 2, 3, 4; +-- test object address functions with recursive dependency walk +-- covers all property graph object types including indirect dependents +SELECT * +FROM ( + WITH RECURSIVE deps (classid, objid, objsubid, refclassid, refobjid, refobjsubid) AS ( + SELECT classid, objid, objsubid, + refclassid, refobjid, refobjsubid + FROM pg_depend + WHERE refclassid = 'pg_class'::regclass AND + refobjid = 'create_property_graph_tests.gt'::regclass + UNION ALL + SELECT d.classid, d.objid, d.objsubid, + d.refclassid, d.refobjid, d.refobjsubid + FROM pg_depend d + JOIN deps dp ON d.refclassid = dp.classid AND d.refobjid = dp.objid AND d.refobjsubid = dp.objsubid + ) + SELECT pg_describe_object(classid, objid, objsubid) as obj, + pg_identify_object(classid, objid, objsubid) as ident, + pg_identify_object_as_address(classid, objid, objsubid) as addr + FROM deps +) s +ORDER BY obj COLLATE "C", ident::text COLLATE "C"; + \a\t SELECT pg_get_propgraphdef('g2'::regclass); SELECT pg_get_propgraphdef('g3'::regclass); diff --git a/src/test/regress/sql/event_trigger.sql b/src/test/regress/sql/event_trigger.sql index 32e9bb58c5e..271f443378b 100644 --- a/src/test/regress/sql/event_trigger.sql +++ b/src/test/regress/sql/event_trigger.sql @@ -143,6 +143,19 @@ create user mapping for regress_evt_user server useless_server; alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +CREATE TABLE t2x (i int PRIMARY KEY, j text); + +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); + +DROP PROPERTY GRAPH gx; +DROP TABLE t1x, t2x; + -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; diff --git a/src/test/regress/sql/object_address.sql b/src/test/regress/sql/object_address.sql index 1bbe9457c1c..27109d421c7 100644 --- a/src/test/regress/sql/object_address.sql +++ b/src/test/regress/sql/object_address.sql @@ -67,7 +67,9 @@ DECLARE BEGIN FOR objtype IN VALUES ('toast table'), ('index column'), ('sequence column'), ('toast table column'), ('view column'), ('materialized view column'), - ('property graph element'), ('property graph label'), ('property graph property') + ('property graph element'), ('property graph element label'), + ('property graph label'), ('property graph label property'), + ('property graph property') LOOP BEGIN PERFORM pg_get_object_address(objtype, '{one}', '{}'); @@ -282,7 +284,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace -- 2.34.1 --R84XrR4Hgw0dH3Ec-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v2] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-23 09:27 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-23 09:27 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing them to hit the default case and error out with "unsupported object class". During DROP PROPERTY GRAPH, this manifests when an event trigger is active, because pg_event_trigger_ddl_commands() calls these functions. The same code paths are also reachable via pg_identify_object() and pg_identify_object_as_address(). This commit adds the missing cases. Test coverage is added in object_address.sql for these two catalog types via the zero-OID test that exercises pg_identify_object() and pg_identify_object_as_address(). A test in event_trigger.sql verifies that DROP PROPERTY GRAPH works correctly when an event trigger is active. Author: Bertrand Drouvot <[email protected]> Reviewed-by: Michael Paquier <[email protected]> Reviewed-by: Ashutosh Bapat <[email protected]> Discussion: https://postgr.es/m/aej1DkLwhyZWmtxJ@bdtpg --- src/backend/catalog/objectaddress.c | 93 ++++++++++++++++++++ src/test/regress/expected/event_trigger.out | 17 ++++ src/test/regress/expected/object_address.out | 4 + src/test/regress/sql/event_trigger.sql | 13 +++ src/test/regress/sql/object_address.sql | 2 + 5 files changed, 129 insertions(+) 62.4% src/backend/catalog/ 25.6% src/test/regress/expected/ 11.8% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/event_trigger.out b/src/test/regress/expected/event_trigger.out index 065f586310f..ed8d5df397e 100644 --- a/src/test/regress/expected/event_trigger.out +++ b/src/test/regress/expected/event_trigger.out @@ -173,6 +173,23 @@ NOTICE: test_event_trigger: ddl_command_end CREATE USER MAPPING alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; NOTICE: test_event_trigger: ddl_command_end ALTER DEFAULT PRIVILEGES +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE TABLE t2x (i int PRIMARY KEY, j text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); +NOTICE: test_event_trigger: ddl_command_end CREATE PROPERTY GRAPH +DROP PROPERTY GRAPH gx; +NOTICE: test_event_trigger: ddl_command_end DROP PROPERTY GRAPH +DROP TABLE t1x, t2x; +NOTICE: test_event_trigger: ddl_command_end DROP TABLE -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; ERROR: permission denied to change owner of event trigger "regress_event_trigger" diff --git a/src/test/regress/expected/object_address.out b/src/test/regress/expected/object_address.out index 97227d67a54..729c3537f25 100644 --- a/src/test/regress/expected/object_address.out +++ b/src/test/regress/expected/object_address.out @@ -593,7 +593,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace @@ -653,6 +655,8 @@ ORDER BY objects.classid, objects.objid, objects.objsubid; ("(""parameter ACL"",,,)")|("(""parameter ACL"",,)")|NULL ("(""property graph element"",,,)")|("(""property graph element"",,)")|NULL ("(""property graph label"",,,)")|("(""property graph label"",,)")|NULL +("(""property graph element label"",,,)")|("(""property graph element label"",,)")|NULL ("(""property graph property"",,,)")|("(""property graph property"",,)")|NULL +("(""property graph label property"",,,)")|("(""property graph label property"",,)")|NULL -- restore normal output mode \a\t diff --git a/src/test/regress/sql/event_trigger.sql b/src/test/regress/sql/event_trigger.sql index 32e9bb58c5e..271f443378b 100644 --- a/src/test/regress/sql/event_trigger.sql +++ b/src/test/regress/sql/event_trigger.sql @@ -143,6 +143,19 @@ create user mapping for regress_evt_user server useless_server; alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +CREATE TABLE t2x (i int PRIMARY KEY, j text); + +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); + +DROP PROPERTY GRAPH gx; +DROP TABLE t1x, t2x; + -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; diff --git a/src/test/regress/sql/object_address.sql b/src/test/regress/sql/object_address.sql index 1bbe9457c1c..620dacf1045 100644 --- a/src/test/regress/sql/object_address.sql +++ b/src/test/regress/sql/object_address.sql @@ -282,7 +282,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace -- 2.34.1 --gtUR827Uq8d5gVsQ-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v2] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-23 09:27 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-23 09:27 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing them to hit the default case and error out with "unsupported object class". During DROP PROPERTY GRAPH, this manifests when an event trigger is active, because pg_event_trigger_ddl_commands() calls these functions. The same code paths are also reachable via pg_identify_object() and pg_identify_object_as_address(). This commit adds the missing cases. Test coverage is added in object_address.sql for these two catalog types via the zero-OID test that exercises pg_identify_object() and pg_identify_object_as_address(). A test in event_trigger.sql verifies that DROP PROPERTY GRAPH works correctly when an event trigger is active. Author: Bertrand Drouvot <[email protected]> Reviewed-by: Michael Paquier <[email protected]> Reviewed-by: Ashutosh Bapat <[email protected]> Discussion: https://postgr.es/m/aej1DkLwhyZWmtxJ@bdtpg --- src/backend/catalog/objectaddress.c | 93 ++++++++++++++++++++ src/test/regress/expected/event_trigger.out | 17 ++++ src/test/regress/expected/object_address.out | 4 + src/test/regress/sql/event_trigger.sql | 13 +++ src/test/regress/sql/object_address.sql | 2 + 5 files changed, 129 insertions(+) 62.4% src/backend/catalog/ 25.6% src/test/regress/expected/ 11.8% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/event_trigger.out b/src/test/regress/expected/event_trigger.out index 065f586310f..ed8d5df397e 100644 --- a/src/test/regress/expected/event_trigger.out +++ b/src/test/regress/expected/event_trigger.out @@ -173,6 +173,23 @@ NOTICE: test_event_trigger: ddl_command_end CREATE USER MAPPING alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; NOTICE: test_event_trigger: ddl_command_end ALTER DEFAULT PRIVILEGES +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE TABLE t2x (i int PRIMARY KEY, j text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); +NOTICE: test_event_trigger: ddl_command_end CREATE PROPERTY GRAPH +DROP PROPERTY GRAPH gx; +NOTICE: test_event_trigger: ddl_command_end DROP PROPERTY GRAPH +DROP TABLE t1x, t2x; +NOTICE: test_event_trigger: ddl_command_end DROP TABLE -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; ERROR: permission denied to change owner of event trigger "regress_event_trigger" diff --git a/src/test/regress/expected/object_address.out b/src/test/regress/expected/object_address.out index 97227d67a54..729c3537f25 100644 --- a/src/test/regress/expected/object_address.out +++ b/src/test/regress/expected/object_address.out @@ -593,7 +593,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace @@ -653,6 +655,8 @@ ORDER BY objects.classid, objects.objid, objects.objsubid; ("(""parameter ACL"",,,)")|("(""parameter ACL"",,)")|NULL ("(""property graph element"",,,)")|("(""property graph element"",,)")|NULL ("(""property graph label"",,,)")|("(""property graph label"",,)")|NULL +("(""property graph element label"",,,)")|("(""property graph element label"",,)")|NULL ("(""property graph property"",,,)")|("(""property graph property"",,)")|NULL +("(""property graph label property"",,,)")|("(""property graph label property"",,)")|NULL -- restore normal output mode \a\t diff --git a/src/test/regress/sql/event_trigger.sql b/src/test/regress/sql/event_trigger.sql index 32e9bb58c5e..271f443378b 100644 --- a/src/test/regress/sql/event_trigger.sql +++ b/src/test/regress/sql/event_trigger.sql @@ -143,6 +143,19 @@ create user mapping for regress_evt_user server useless_server; alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +CREATE TABLE t2x (i int PRIMARY KEY, j text); + +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); + +DROP PROPERTY GRAPH gx; +DROP TABLE t1x, t2x; + -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; diff --git a/src/test/regress/sql/object_address.sql b/src/test/regress/sql/object_address.sql index 1bbe9457c1c..620dacf1045 100644 --- a/src/test/regress/sql/object_address.sql +++ b/src/test/regress/sql/object_address.sql @@ -282,7 +282,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace -- 2.34.1 --gtUR827Uq8d5gVsQ-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v2] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-23 09:27 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-23 09:27 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing them to hit the default case and error out with "unsupported object class". During DROP PROPERTY GRAPH, this manifests when an event trigger is active, because pg_event_trigger_ddl_commands() calls these functions. The same code paths are also reachable via pg_identify_object() and pg_identify_object_as_address(). This commit adds the missing cases. Test coverage is added in object_address.sql for these two catalog types via the zero-OID test that exercises pg_identify_object() and pg_identify_object_as_address(). A test in event_trigger.sql verifies that DROP PROPERTY GRAPH works correctly when an event trigger is active. Author: Bertrand Drouvot <[email protected]> Reviewed-by: Michael Paquier <[email protected]> Reviewed-by: Ashutosh Bapat <[email protected]> Discussion: https://postgr.es/m/aej1DkLwhyZWmtxJ@bdtpg --- src/backend/catalog/objectaddress.c | 93 ++++++++++++++++++++ src/test/regress/expected/event_trigger.out | 17 ++++ src/test/regress/expected/object_address.out | 4 + src/test/regress/sql/event_trigger.sql | 13 +++ src/test/regress/sql/object_address.sql | 2 + 5 files changed, 129 insertions(+) 62.4% src/backend/catalog/ 25.6% src/test/regress/expected/ 11.8% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/event_trigger.out b/src/test/regress/expected/event_trigger.out index 065f586310f..ed8d5df397e 100644 --- a/src/test/regress/expected/event_trigger.out +++ b/src/test/regress/expected/event_trigger.out @@ -173,6 +173,23 @@ NOTICE: test_event_trigger: ddl_command_end CREATE USER MAPPING alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; NOTICE: test_event_trigger: ddl_command_end ALTER DEFAULT PRIVILEGES +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE TABLE t2x (i int PRIMARY KEY, j text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); +NOTICE: test_event_trigger: ddl_command_end CREATE PROPERTY GRAPH +DROP PROPERTY GRAPH gx; +NOTICE: test_event_trigger: ddl_command_end DROP PROPERTY GRAPH +DROP TABLE t1x, t2x; +NOTICE: test_event_trigger: ddl_command_end DROP TABLE -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; ERROR: permission denied to change owner of event trigger "regress_event_trigger" diff --git a/src/test/regress/expected/object_address.out b/src/test/regress/expected/object_address.out index 97227d67a54..729c3537f25 100644 --- a/src/test/regress/expected/object_address.out +++ b/src/test/regress/expected/object_address.out @@ -593,7 +593,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace @@ -653,6 +655,8 @@ ORDER BY objects.classid, objects.objid, objects.objsubid; ("(""parameter ACL"",,,)")|("(""parameter ACL"",,)")|NULL ("(""property graph element"",,,)")|("(""property graph element"",,)")|NULL ("(""property graph label"",,,)")|("(""property graph label"",,)")|NULL +("(""property graph element label"",,,)")|("(""property graph element label"",,)")|NULL ("(""property graph property"",,,)")|("(""property graph property"",,)")|NULL +("(""property graph label property"",,,)")|("(""property graph label property"",,)")|NULL -- restore normal output mode \a\t diff --git a/src/test/regress/sql/event_trigger.sql b/src/test/regress/sql/event_trigger.sql index 32e9bb58c5e..271f443378b 100644 --- a/src/test/regress/sql/event_trigger.sql +++ b/src/test/regress/sql/event_trigger.sql @@ -143,6 +143,19 @@ create user mapping for regress_evt_user server useless_server; alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +CREATE TABLE t2x (i int PRIMARY KEY, j text); + +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); + +DROP PROPERTY GRAPH gx; +DROP TABLE t1x, t2x; + -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; diff --git a/src/test/regress/sql/object_address.sql b/src/test/regress/sql/object_address.sql index 1bbe9457c1c..620dacf1045 100644 --- a/src/test/regress/sql/object_address.sql +++ b/src/test/regress/sql/object_address.sql @@ -282,7 +282,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace -- 2.34.1 --gtUR827Uq8d5gVsQ-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v2] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-23 09:27 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-23 09:27 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing them to hit the default case and error out with "unsupported object class". During DROP PROPERTY GRAPH, this manifests when an event trigger is active, because pg_event_trigger_ddl_commands() calls these functions. The same code paths are also reachable via pg_identify_object() and pg_identify_object_as_address(). This commit adds the missing cases. Test coverage is added in object_address.sql for these two catalog types via the zero-OID test that exercises pg_identify_object() and pg_identify_object_as_address(). A test in event_trigger.sql verifies that DROP PROPERTY GRAPH works correctly when an event trigger is active. Author: Bertrand Drouvot <[email protected]> Reviewed-by: Michael Paquier <[email protected]> Reviewed-by: Ashutosh Bapat <[email protected]> Discussion: https://postgr.es/m/aej1DkLwhyZWmtxJ@bdtpg --- src/backend/catalog/objectaddress.c | 93 ++++++++++++++++++++ src/test/regress/expected/event_trigger.out | 17 ++++ src/test/regress/expected/object_address.out | 4 + src/test/regress/sql/event_trigger.sql | 13 +++ src/test/regress/sql/object_address.sql | 2 + 5 files changed, 129 insertions(+) 62.4% src/backend/catalog/ 25.6% src/test/regress/expected/ 11.8% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/event_trigger.out b/src/test/regress/expected/event_trigger.out index 065f586310f..ed8d5df397e 100644 --- a/src/test/regress/expected/event_trigger.out +++ b/src/test/regress/expected/event_trigger.out @@ -173,6 +173,23 @@ NOTICE: test_event_trigger: ddl_command_end CREATE USER MAPPING alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; NOTICE: test_event_trigger: ddl_command_end ALTER DEFAULT PRIVILEGES +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE TABLE t2x (i int PRIMARY KEY, j text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); +NOTICE: test_event_trigger: ddl_command_end CREATE PROPERTY GRAPH +DROP PROPERTY GRAPH gx; +NOTICE: test_event_trigger: ddl_command_end DROP PROPERTY GRAPH +DROP TABLE t1x, t2x; +NOTICE: test_event_trigger: ddl_command_end DROP TABLE -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; ERROR: permission denied to change owner of event trigger "regress_event_trigger" diff --git a/src/test/regress/expected/object_address.out b/src/test/regress/expected/object_address.out index 97227d67a54..729c3537f25 100644 --- a/src/test/regress/expected/object_address.out +++ b/src/test/regress/expected/object_address.out @@ -593,7 +593,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace @@ -653,6 +655,8 @@ ORDER BY objects.classid, objects.objid, objects.objsubid; ("(""parameter ACL"",,,)")|("(""parameter ACL"",,)")|NULL ("(""property graph element"",,,)")|("(""property graph element"",,)")|NULL ("(""property graph label"",,,)")|("(""property graph label"",,)")|NULL +("(""property graph element label"",,,)")|("(""property graph element label"",,)")|NULL ("(""property graph property"",,,)")|("(""property graph property"",,)")|NULL +("(""property graph label property"",,,)")|("(""property graph label property"",,)")|NULL -- restore normal output mode \a\t diff --git a/src/test/regress/sql/event_trigger.sql b/src/test/regress/sql/event_trigger.sql index 32e9bb58c5e..271f443378b 100644 --- a/src/test/regress/sql/event_trigger.sql +++ b/src/test/regress/sql/event_trigger.sql @@ -143,6 +143,19 @@ create user mapping for regress_evt_user server useless_server; alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +CREATE TABLE t2x (i int PRIMARY KEY, j text); + +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); + +DROP PROPERTY GRAPH gx; +DROP TABLE t1x, t2x; + -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; diff --git a/src/test/regress/sql/object_address.sql b/src/test/regress/sql/object_address.sql index 1bbe9457c1c..620dacf1045 100644 --- a/src/test/regress/sql/object_address.sql +++ b/src/test/regress/sql/object_address.sql @@ -282,7 +282,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace -- 2.34.1 --gtUR827Uq8d5gVsQ-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v3] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-23 09:27 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-23 09:27 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing them to hit the default case and error out with "unsupported object class". During DROP PROPERTY GRAPH, this manifests when an event trigger is active, because pg_event_trigger_ddl_commands() calls these functions. The same code paths are also reachable via pg_identify_object() and pg_identify_object_as_address(). This commit adds the missing cases. Test coverage is added in object_address.sql for these two catalog types and in create_property_graph.sql covering all property graph object types. A test in event_trigger.sql verifies that DROP PROPERTY GRAPH works correctly when an event trigger is active. Author: Bertrand Drouvot <[email protected]> Reviewed-by: Michael Paquier <[email protected]> Reviewed-by: Ashutosh Bapat <[email protected]> Discussion: https://postgr.es/m/aej1DkLwhyZWmtxJ@bdtpg --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 78 ++++++++++++++++ src/test/regress/expected/event_trigger.out | 17 ++++ src/test/regress/expected/object_address.out | 10 +- .../regress/sql/create_property_graph.sql | 23 +++++ src/test/regress/sql/event_trigger.sql | 13 +++ src/test/regress/sql/object_address.sql | 6 +- 7 files changed, 238 insertions(+), 2 deletions(-) 14.7% src/backend/catalog/ 75.5% src/test/regress/expected/ 9.7% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..eb9e17fb727 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -752,6 +752,84 @@ SELECT (pg_identify_object(classid, objid, objsubid)).* type | create_property_graph_tests | g2 | create_property_graph_tests.g2 (21 rows) +-- test object address functions with recursive dependency walk +-- covers all property graph object types including indirect dependents +SELECT * +FROM ( + WITH RECURSIVE deps (classid, objid, objsubid, refclassid, refobjid, refobjsubid) AS ( + SELECT classid, objid, objsubid, + refclassid, refobjid, refobjsubid + FROM pg_depend + WHERE refclassid = 'pg_class'::regclass AND + refobjid = 'create_property_graph_tests.gt'::regclass + UNION ALL + SELECT d.classid, d.objid, d.objsubid, + d.refclassid, d.refobjid, d.refobjsubid + FROM pg_depend d + JOIN deps dp ON d.refclassid = dp.classid AND d.refobjid = dp.objid AND d.refobjsubid = dp.objsubid + ) + SELECT pg_describe_object(classid, objid, objsubid) as obj, + pg_identify_object(classid, objid, objsubid) as ident, + pg_identify_object_as_address(classid, objid, objsubid) as addr + FROM deps +) s +ORDER BY obj COLLATE "C", ident::text COLLATE "C"; + obj | ident | addr +----------------------------------------------------------+----------------------------------------------------------------------------+---------------------------------------------------------------------------- + edge e of property graph gt | ("property graph element",,,"e of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,e}",{}) + edge e of property graph gt | ("property graph element",,,"e of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,e}",{}) + edge e of property graph gt | ("property graph element",,,"e of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of property graph gt | ("property graph label",,,"e of create_property_graph_tests.gt") | ("property graph label","{create_property_graph_tests,gt,e}",{}) + label v1 of property graph gt | ("property graph label",,,"v1 of create_property_graph_tests.gt") | ("property graph label","{create_property_graph_tests,gt,v1}",{}) + label v1 of vertex v1 of property graph gt | ("property graph element label",,,"v1 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v1}",{}) + label v1 of vertex v1 of property graph gt | ("property graph element label",,,"v1 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v1}",{}) + label v2 of property graph gt | ("property graph label",,,"v2 of create_property_graph_tests.gt") | ("property graph label","{create_property_graph_tests,gt,v2}",{}) + label v2 of vertex v2 of property graph gt | ("property graph element label",,,"v2 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v2}",{}) + label v2 of vertex v2 of property graph gt | ("property graph element label",,,"v2 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v2}",{}) + property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property a of property graph gt | ("property graph property",,,"a of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,a}",{}) + property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property b of property graph gt | ("property graph property",,,"b of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,b}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of property graph gt | ("property graph property",,,"c of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,c}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of property graph gt | ("property graph property",,,"k1 of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,k1}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of property graph gt | ("property graph property",,,"k2 of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,k2}",{}) + property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property m of property graph gt | ("property graph property",,,"m of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,m}",{}) + property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property n of property graph gt | ("property graph property",,,"n of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,n}",{}) + type gt | (type,create_property_graph_tests,gt,create_property_graph_tests.gt) | (type,{create_property_graph_tests.gt},{}) + type gt[] | (type,create_property_graph_tests,_gt,create_property_graph_tests.gt[]) | (type,{create_property_graph_tests.gt[]},{}) + vertex v1 of property graph gt | ("property graph element",,,"v1 of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,v1}",{}) + vertex v2 of property graph gt | ("property graph element",,,"v2 of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,v2}",{}) +(52 rows) + \a\t SELECT pg_get_propgraphdef('g2'::regclass); CREATE PROPERTY GRAPH create_property_graph_tests.g2 diff --git a/src/test/regress/expected/event_trigger.out b/src/test/regress/expected/event_trigger.out index 065f586310f..ed8d5df397e 100644 --- a/src/test/regress/expected/event_trigger.out +++ b/src/test/regress/expected/event_trigger.out @@ -173,6 +173,23 @@ NOTICE: test_event_trigger: ddl_command_end CREATE USER MAPPING alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; NOTICE: test_event_trigger: ddl_command_end ALTER DEFAULT PRIVILEGES +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE TABLE t2x (i int PRIMARY KEY, j text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); +NOTICE: test_event_trigger: ddl_command_end CREATE PROPERTY GRAPH +DROP PROPERTY GRAPH gx; +NOTICE: test_event_trigger: ddl_command_end DROP PROPERTY GRAPH +DROP TABLE t1x, t2x; +NOTICE: test_event_trigger: ddl_command_end DROP TABLE -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; ERROR: permission denied to change owner of event trigger "regress_event_trigger" diff --git a/src/test/regress/expected/object_address.out b/src/test/regress/expected/object_address.out index 97227d67a54..5e53f0b092e 100644 --- a/src/test/regress/expected/object_address.out +++ b/src/test/regress/expected/object_address.out @@ -67,7 +67,9 @@ DECLARE BEGIN FOR objtype IN VALUES ('toast table'), ('index column'), ('sequence column'), ('toast table column'), ('view column'), ('materialized view column'), - ('property graph element'), ('property graph label'), ('property graph property') + ('property graph element'), ('property graph element label'), + ('property graph label'), ('property graph label property'), + ('property graph property') LOOP BEGIN PERFORM pg_get_object_address(objtype, '{one}', '{}'); @@ -84,7 +86,9 @@ WARNING: error for toast table column: unsupported object type "toast table col WARNING: error for view column: unsupported object type "view column" WARNING: error for materialized view column: unsupported object type "materialized view column" WARNING: error for property graph element: unsupported object type "property graph element" +WARNING: error for property graph element label: unrecognized object type "property graph element label" WARNING: error for property graph label: unsupported object type "property graph label" +WARNING: error for property graph label property: unrecognized object type "property graph label property" WARNING: error for property graph property: unsupported object type "property graph property" -- miscellaneous other errors select * from pg_get_object_address('operator of access method', '{btree,integer_ops,1}', '{int4,bool}'); @@ -593,7 +597,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace @@ -653,6 +659,8 @@ ORDER BY objects.classid, objects.objid, objects.objsubid; ("(""parameter ACL"",,,)")|("(""parameter ACL"",,)")|NULL ("(""property graph element"",,,)")|("(""property graph element"",,)")|NULL ("(""property graph label"",,,)")|("(""property graph label"",,)")|NULL +("(""property graph element label"",,,)")|("(""property graph element label"",,)")|NULL ("(""property graph property"",,,)")|("(""property graph property"",,)")|NULL +("(""property graph label property"",,,)")|("(""property graph label property"",,)")|NULL -- restore normal output mode \a\t diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..9608dd5c4af 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -298,6 +298,29 @@ SELECT (pg_identify_object(classid, objid, objsubid)).* refobjid = 'create_property_graph_tests.g2'::regclass ORDER BY 1, 2, 3, 4; +-- test object address functions with recursive dependency walk +-- covers all property graph object types including indirect dependents +SELECT * +FROM ( + WITH RECURSIVE deps (classid, objid, objsubid, refclassid, refobjid, refobjsubid) AS ( + SELECT classid, objid, objsubid, + refclassid, refobjid, refobjsubid + FROM pg_depend + WHERE refclassid = 'pg_class'::regclass AND + refobjid = 'create_property_graph_tests.gt'::regclass + UNION ALL + SELECT d.classid, d.objid, d.objsubid, + d.refclassid, d.refobjid, d.refobjsubid + FROM pg_depend d + JOIN deps dp ON d.refclassid = dp.classid AND d.refobjid = dp.objid AND d.refobjsubid = dp.objsubid + ) + SELECT pg_describe_object(classid, objid, objsubid) as obj, + pg_identify_object(classid, objid, objsubid) as ident, + pg_identify_object_as_address(classid, objid, objsubid) as addr + FROM deps +) s +ORDER BY obj COLLATE "C", ident::text COLLATE "C"; + \a\t SELECT pg_get_propgraphdef('g2'::regclass); SELECT pg_get_propgraphdef('g3'::regclass); diff --git a/src/test/regress/sql/event_trigger.sql b/src/test/regress/sql/event_trigger.sql index 32e9bb58c5e..271f443378b 100644 --- a/src/test/regress/sql/event_trigger.sql +++ b/src/test/regress/sql/event_trigger.sql @@ -143,6 +143,19 @@ create user mapping for regress_evt_user server useless_server; alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +CREATE TABLE t2x (i int PRIMARY KEY, j text); + +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); + +DROP PROPERTY GRAPH gx; +DROP TABLE t1x, t2x; + -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; diff --git a/src/test/regress/sql/object_address.sql b/src/test/regress/sql/object_address.sql index 1bbe9457c1c..27109d421c7 100644 --- a/src/test/regress/sql/object_address.sql +++ b/src/test/regress/sql/object_address.sql @@ -67,7 +67,9 @@ DECLARE BEGIN FOR objtype IN VALUES ('toast table'), ('index column'), ('sequence column'), ('toast table column'), ('view column'), ('materialized view column'), - ('property graph element'), ('property graph label'), ('property graph property') + ('property graph element'), ('property graph element label'), + ('property graph label'), ('property graph label property'), + ('property graph property') LOOP BEGIN PERFORM pg_get_object_address(objtype, '{one}', '{}'); @@ -282,7 +284,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace -- 2.34.1 --R84XrR4Hgw0dH3Ec-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v2] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-23 09:27 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-23 09:27 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing them to hit the default case and error out with "unsupported object class". During DROP PROPERTY GRAPH, this manifests when an event trigger is active, because pg_event_trigger_ddl_commands() calls these functions. The same code paths are also reachable via pg_identify_object() and pg_identify_object_as_address(). This commit adds the missing cases. Test coverage is added in object_address.sql for these two catalog types via the zero-OID test that exercises pg_identify_object() and pg_identify_object_as_address(). A test in event_trigger.sql verifies that DROP PROPERTY GRAPH works correctly when an event trigger is active. Author: Bertrand Drouvot <[email protected]> Reviewed-by: Michael Paquier <[email protected]> Reviewed-by: Ashutosh Bapat <[email protected]> Discussion: https://postgr.es/m/aej1DkLwhyZWmtxJ@bdtpg --- src/backend/catalog/objectaddress.c | 93 ++++++++++++++++++++ src/test/regress/expected/event_trigger.out | 17 ++++ src/test/regress/expected/object_address.out | 4 + src/test/regress/sql/event_trigger.sql | 13 +++ src/test/regress/sql/object_address.sql | 2 + 5 files changed, 129 insertions(+) 62.4% src/backend/catalog/ 25.6% src/test/regress/expected/ 11.8% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/event_trigger.out b/src/test/regress/expected/event_trigger.out index 065f586310f..ed8d5df397e 100644 --- a/src/test/regress/expected/event_trigger.out +++ b/src/test/regress/expected/event_trigger.out @@ -173,6 +173,23 @@ NOTICE: test_event_trigger: ddl_command_end CREATE USER MAPPING alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; NOTICE: test_event_trigger: ddl_command_end ALTER DEFAULT PRIVILEGES +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE TABLE t2x (i int PRIMARY KEY, j text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); +NOTICE: test_event_trigger: ddl_command_end CREATE PROPERTY GRAPH +DROP PROPERTY GRAPH gx; +NOTICE: test_event_trigger: ddl_command_end DROP PROPERTY GRAPH +DROP TABLE t1x, t2x; +NOTICE: test_event_trigger: ddl_command_end DROP TABLE -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; ERROR: permission denied to change owner of event trigger "regress_event_trigger" diff --git a/src/test/regress/expected/object_address.out b/src/test/regress/expected/object_address.out index 97227d67a54..729c3537f25 100644 --- a/src/test/regress/expected/object_address.out +++ b/src/test/regress/expected/object_address.out @@ -593,7 +593,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace @@ -653,6 +655,8 @@ ORDER BY objects.classid, objects.objid, objects.objsubid; ("(""parameter ACL"",,,)")|("(""parameter ACL"",,)")|NULL ("(""property graph element"",,,)")|("(""property graph element"",,)")|NULL ("(""property graph label"",,,)")|("(""property graph label"",,)")|NULL +("(""property graph element label"",,,)")|("(""property graph element label"",,)")|NULL ("(""property graph property"",,,)")|("(""property graph property"",,)")|NULL +("(""property graph label property"",,,)")|("(""property graph label property"",,)")|NULL -- restore normal output mode \a\t diff --git a/src/test/regress/sql/event_trigger.sql b/src/test/regress/sql/event_trigger.sql index 32e9bb58c5e..271f443378b 100644 --- a/src/test/regress/sql/event_trigger.sql +++ b/src/test/regress/sql/event_trigger.sql @@ -143,6 +143,19 @@ create user mapping for regress_evt_user server useless_server; alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +CREATE TABLE t2x (i int PRIMARY KEY, j text); + +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); + +DROP PROPERTY GRAPH gx; +DROP TABLE t1x, t2x; + -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; diff --git a/src/test/regress/sql/object_address.sql b/src/test/regress/sql/object_address.sql index 1bbe9457c1c..620dacf1045 100644 --- a/src/test/regress/sql/object_address.sql +++ b/src/test/regress/sql/object_address.sql @@ -282,7 +282,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace -- 2.34.1 --gtUR827Uq8d5gVsQ-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v3] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-23 09:27 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-23 09:27 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing them to hit the default case and error out with "unsupported object class". During DROP PROPERTY GRAPH, this manifests when an event trigger is active, because pg_event_trigger_ddl_commands() calls these functions. The same code paths are also reachable via pg_identify_object() and pg_identify_object_as_address(). This commit adds the missing cases. Test coverage is added in object_address.sql for these two catalog types and in create_property_graph.sql covering all property graph object types. A test in event_trigger.sql verifies that DROP PROPERTY GRAPH works correctly when an event trigger is active. Author: Bertrand Drouvot <[email protected]> Reviewed-by: Michael Paquier <[email protected]> Reviewed-by: Ashutosh Bapat <[email protected]> Discussion: https://postgr.es/m/aej1DkLwhyZWmtxJ@bdtpg --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 78 ++++++++++++++++ src/test/regress/expected/event_trigger.out | 17 ++++ src/test/regress/expected/object_address.out | 10 +- .../regress/sql/create_property_graph.sql | 23 +++++ src/test/regress/sql/event_trigger.sql | 13 +++ src/test/regress/sql/object_address.sql | 6 +- 7 files changed, 238 insertions(+), 2 deletions(-) 14.7% src/backend/catalog/ 75.5% src/test/regress/expected/ 9.7% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..eb9e17fb727 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -752,6 +752,84 @@ SELECT (pg_identify_object(classid, objid, objsubid)).* type | create_property_graph_tests | g2 | create_property_graph_tests.g2 (21 rows) +-- test object address functions with recursive dependency walk +-- covers all property graph object types including indirect dependents +SELECT * +FROM ( + WITH RECURSIVE deps (classid, objid, objsubid, refclassid, refobjid, refobjsubid) AS ( + SELECT classid, objid, objsubid, + refclassid, refobjid, refobjsubid + FROM pg_depend + WHERE refclassid = 'pg_class'::regclass AND + refobjid = 'create_property_graph_tests.gt'::regclass + UNION ALL + SELECT d.classid, d.objid, d.objsubid, + d.refclassid, d.refobjid, d.refobjsubid + FROM pg_depend d + JOIN deps dp ON d.refclassid = dp.classid AND d.refobjid = dp.objid AND d.refobjsubid = dp.objsubid + ) + SELECT pg_describe_object(classid, objid, objsubid) as obj, + pg_identify_object(classid, objid, objsubid) as ident, + pg_identify_object_as_address(classid, objid, objsubid) as addr + FROM deps +) s +ORDER BY obj COLLATE "C", ident::text COLLATE "C"; + obj | ident | addr +----------------------------------------------------------+----------------------------------------------------------------------------+---------------------------------------------------------------------------- + edge e of property graph gt | ("property graph element",,,"e of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,e}",{}) + edge e of property graph gt | ("property graph element",,,"e of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,e}",{}) + edge e of property graph gt | ("property graph element",,,"e of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of property graph gt | ("property graph label",,,"e of create_property_graph_tests.gt") | ("property graph label","{create_property_graph_tests,gt,e}",{}) + label v1 of property graph gt | ("property graph label",,,"v1 of create_property_graph_tests.gt") | ("property graph label","{create_property_graph_tests,gt,v1}",{}) + label v1 of vertex v1 of property graph gt | ("property graph element label",,,"v1 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v1}",{}) + label v1 of vertex v1 of property graph gt | ("property graph element label",,,"v1 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v1}",{}) + label v2 of property graph gt | ("property graph label",,,"v2 of create_property_graph_tests.gt") | ("property graph label","{create_property_graph_tests,gt,v2}",{}) + label v2 of vertex v2 of property graph gt | ("property graph element label",,,"v2 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v2}",{}) + label v2 of vertex v2 of property graph gt | ("property graph element label",,,"v2 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v2}",{}) + property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property a of property graph gt | ("property graph property",,,"a of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,a}",{}) + property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property b of property graph gt | ("property graph property",,,"b of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,b}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of property graph gt | ("property graph property",,,"c of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,c}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of property graph gt | ("property graph property",,,"k1 of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,k1}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of property graph gt | ("property graph property",,,"k2 of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,k2}",{}) + property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property m of property graph gt | ("property graph property",,,"m of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,m}",{}) + property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property n of property graph gt | ("property graph property",,,"n of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,n}",{}) + type gt | (type,create_property_graph_tests,gt,create_property_graph_tests.gt) | (type,{create_property_graph_tests.gt},{}) + type gt[] | (type,create_property_graph_tests,_gt,create_property_graph_tests.gt[]) | (type,{create_property_graph_tests.gt[]},{}) + vertex v1 of property graph gt | ("property graph element",,,"v1 of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,v1}",{}) + vertex v2 of property graph gt | ("property graph element",,,"v2 of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,v2}",{}) +(52 rows) + \a\t SELECT pg_get_propgraphdef('g2'::regclass); CREATE PROPERTY GRAPH create_property_graph_tests.g2 diff --git a/src/test/regress/expected/event_trigger.out b/src/test/regress/expected/event_trigger.out index 065f586310f..ed8d5df397e 100644 --- a/src/test/regress/expected/event_trigger.out +++ b/src/test/regress/expected/event_trigger.out @@ -173,6 +173,23 @@ NOTICE: test_event_trigger: ddl_command_end CREATE USER MAPPING alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; NOTICE: test_event_trigger: ddl_command_end ALTER DEFAULT PRIVILEGES +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE TABLE t2x (i int PRIMARY KEY, j text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); +NOTICE: test_event_trigger: ddl_command_end CREATE PROPERTY GRAPH +DROP PROPERTY GRAPH gx; +NOTICE: test_event_trigger: ddl_command_end DROP PROPERTY GRAPH +DROP TABLE t1x, t2x; +NOTICE: test_event_trigger: ddl_command_end DROP TABLE -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; ERROR: permission denied to change owner of event trigger "regress_event_trigger" diff --git a/src/test/regress/expected/object_address.out b/src/test/regress/expected/object_address.out index 97227d67a54..5e53f0b092e 100644 --- a/src/test/regress/expected/object_address.out +++ b/src/test/regress/expected/object_address.out @@ -67,7 +67,9 @@ DECLARE BEGIN FOR objtype IN VALUES ('toast table'), ('index column'), ('sequence column'), ('toast table column'), ('view column'), ('materialized view column'), - ('property graph element'), ('property graph label'), ('property graph property') + ('property graph element'), ('property graph element label'), + ('property graph label'), ('property graph label property'), + ('property graph property') LOOP BEGIN PERFORM pg_get_object_address(objtype, '{one}', '{}'); @@ -84,7 +86,9 @@ WARNING: error for toast table column: unsupported object type "toast table col WARNING: error for view column: unsupported object type "view column" WARNING: error for materialized view column: unsupported object type "materialized view column" WARNING: error for property graph element: unsupported object type "property graph element" +WARNING: error for property graph element label: unrecognized object type "property graph element label" WARNING: error for property graph label: unsupported object type "property graph label" +WARNING: error for property graph label property: unrecognized object type "property graph label property" WARNING: error for property graph property: unsupported object type "property graph property" -- miscellaneous other errors select * from pg_get_object_address('operator of access method', '{btree,integer_ops,1}', '{int4,bool}'); @@ -593,7 +597,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace @@ -653,6 +659,8 @@ ORDER BY objects.classid, objects.objid, objects.objsubid; ("(""parameter ACL"",,,)")|("(""parameter ACL"",,)")|NULL ("(""property graph element"",,,)")|("(""property graph element"",,)")|NULL ("(""property graph label"",,,)")|("(""property graph label"",,)")|NULL +("(""property graph element label"",,,)")|("(""property graph element label"",,)")|NULL ("(""property graph property"",,,)")|("(""property graph property"",,)")|NULL +("(""property graph label property"",,,)")|("(""property graph label property"",,)")|NULL -- restore normal output mode \a\t diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..9608dd5c4af 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -298,6 +298,29 @@ SELECT (pg_identify_object(classid, objid, objsubid)).* refobjid = 'create_property_graph_tests.g2'::regclass ORDER BY 1, 2, 3, 4; +-- test object address functions with recursive dependency walk +-- covers all property graph object types including indirect dependents +SELECT * +FROM ( + WITH RECURSIVE deps (classid, objid, objsubid, refclassid, refobjid, refobjsubid) AS ( + SELECT classid, objid, objsubid, + refclassid, refobjid, refobjsubid + FROM pg_depend + WHERE refclassid = 'pg_class'::regclass AND + refobjid = 'create_property_graph_tests.gt'::regclass + UNION ALL + SELECT d.classid, d.objid, d.objsubid, + d.refclassid, d.refobjid, d.refobjsubid + FROM pg_depend d + JOIN deps dp ON d.refclassid = dp.classid AND d.refobjid = dp.objid AND d.refobjsubid = dp.objsubid + ) + SELECT pg_describe_object(classid, objid, objsubid) as obj, + pg_identify_object(classid, objid, objsubid) as ident, + pg_identify_object_as_address(classid, objid, objsubid) as addr + FROM deps +) s +ORDER BY obj COLLATE "C", ident::text COLLATE "C"; + \a\t SELECT pg_get_propgraphdef('g2'::regclass); SELECT pg_get_propgraphdef('g3'::regclass); diff --git a/src/test/regress/sql/event_trigger.sql b/src/test/regress/sql/event_trigger.sql index 32e9bb58c5e..271f443378b 100644 --- a/src/test/regress/sql/event_trigger.sql +++ b/src/test/regress/sql/event_trigger.sql @@ -143,6 +143,19 @@ create user mapping for regress_evt_user server useless_server; alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +CREATE TABLE t2x (i int PRIMARY KEY, j text); + +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); + +DROP PROPERTY GRAPH gx; +DROP TABLE t1x, t2x; + -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; diff --git a/src/test/regress/sql/object_address.sql b/src/test/regress/sql/object_address.sql index 1bbe9457c1c..27109d421c7 100644 --- a/src/test/regress/sql/object_address.sql +++ b/src/test/regress/sql/object_address.sql @@ -67,7 +67,9 @@ DECLARE BEGIN FOR objtype IN VALUES ('toast table'), ('index column'), ('sequence column'), ('toast table column'), ('view column'), ('materialized view column'), - ('property graph element'), ('property graph label'), ('property graph property') + ('property graph element'), ('property graph element label'), + ('property graph label'), ('property graph label property'), + ('property graph property') LOOP BEGIN PERFORM pg_get_object_address(objtype, '{one}', '{}'); @@ -282,7 +284,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace -- 2.34.1 --R84XrR4Hgw0dH3Ec-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v2] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-23 09:27 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-23 09:27 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing them to hit the default case and error out with "unsupported object class". During DROP PROPERTY GRAPH, this manifests when an event trigger is active, because pg_event_trigger_ddl_commands() calls these functions. The same code paths are also reachable via pg_identify_object() and pg_identify_object_as_address(). This commit adds the missing cases. Test coverage is added in object_address.sql for these two catalog types via the zero-OID test that exercises pg_identify_object() and pg_identify_object_as_address(). A test in event_trigger.sql verifies that DROP PROPERTY GRAPH works correctly when an event trigger is active. Author: Bertrand Drouvot <[email protected]> Reviewed-by: Michael Paquier <[email protected]> Reviewed-by: Ashutosh Bapat <[email protected]> Discussion: https://postgr.es/m/aej1DkLwhyZWmtxJ@bdtpg --- src/backend/catalog/objectaddress.c | 93 ++++++++++++++++++++ src/test/regress/expected/event_trigger.out | 17 ++++ src/test/regress/expected/object_address.out | 4 + src/test/regress/sql/event_trigger.sql | 13 +++ src/test/regress/sql/object_address.sql | 2 + 5 files changed, 129 insertions(+) 62.4% src/backend/catalog/ 25.6% src/test/regress/expected/ 11.8% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/event_trigger.out b/src/test/regress/expected/event_trigger.out index 065f586310f..ed8d5df397e 100644 --- a/src/test/regress/expected/event_trigger.out +++ b/src/test/regress/expected/event_trigger.out @@ -173,6 +173,23 @@ NOTICE: test_event_trigger: ddl_command_end CREATE USER MAPPING alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; NOTICE: test_event_trigger: ddl_command_end ALTER DEFAULT PRIVILEGES +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE TABLE t2x (i int PRIMARY KEY, j text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); +NOTICE: test_event_trigger: ddl_command_end CREATE PROPERTY GRAPH +DROP PROPERTY GRAPH gx; +NOTICE: test_event_trigger: ddl_command_end DROP PROPERTY GRAPH +DROP TABLE t1x, t2x; +NOTICE: test_event_trigger: ddl_command_end DROP TABLE -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; ERROR: permission denied to change owner of event trigger "regress_event_trigger" diff --git a/src/test/regress/expected/object_address.out b/src/test/regress/expected/object_address.out index 97227d67a54..729c3537f25 100644 --- a/src/test/regress/expected/object_address.out +++ b/src/test/regress/expected/object_address.out @@ -593,7 +593,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace @@ -653,6 +655,8 @@ ORDER BY objects.classid, objects.objid, objects.objsubid; ("(""parameter ACL"",,,)")|("(""parameter ACL"",,)")|NULL ("(""property graph element"",,,)")|("(""property graph element"",,)")|NULL ("(""property graph label"",,,)")|("(""property graph label"",,)")|NULL +("(""property graph element label"",,,)")|("(""property graph element label"",,)")|NULL ("(""property graph property"",,,)")|("(""property graph property"",,)")|NULL +("(""property graph label property"",,,)")|("(""property graph label property"",,)")|NULL -- restore normal output mode \a\t diff --git a/src/test/regress/sql/event_trigger.sql b/src/test/regress/sql/event_trigger.sql index 32e9bb58c5e..271f443378b 100644 --- a/src/test/regress/sql/event_trigger.sql +++ b/src/test/regress/sql/event_trigger.sql @@ -143,6 +143,19 @@ create user mapping for regress_evt_user server useless_server; alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +CREATE TABLE t2x (i int PRIMARY KEY, j text); + +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); + +DROP PROPERTY GRAPH gx; +DROP TABLE t1x, t2x; + -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; diff --git a/src/test/regress/sql/object_address.sql b/src/test/regress/sql/object_address.sql index 1bbe9457c1c..620dacf1045 100644 --- a/src/test/regress/sql/object_address.sql +++ b/src/test/regress/sql/object_address.sql @@ -282,7 +282,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace -- 2.34.1 --gtUR827Uq8d5gVsQ-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v3] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-23 09:27 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-23 09:27 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing them to hit the default case and error out with "unsupported object class". During DROP PROPERTY GRAPH, this manifests when an event trigger is active, because pg_event_trigger_ddl_commands() calls these functions. The same code paths are also reachable via pg_identify_object() and pg_identify_object_as_address(). This commit adds the missing cases. Test coverage is added in object_address.sql for these two catalog types and in create_property_graph.sql covering all property graph object types. A test in event_trigger.sql verifies that DROP PROPERTY GRAPH works correctly when an event trigger is active. Author: Bertrand Drouvot <[email protected]> Reviewed-by: Michael Paquier <[email protected]> Reviewed-by: Ashutosh Bapat <[email protected]> Discussion: https://postgr.es/m/aej1DkLwhyZWmtxJ@bdtpg --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 78 ++++++++++++++++ src/test/regress/expected/event_trigger.out | 17 ++++ src/test/regress/expected/object_address.out | 10 +- .../regress/sql/create_property_graph.sql | 23 +++++ src/test/regress/sql/event_trigger.sql | 13 +++ src/test/regress/sql/object_address.sql | 6 +- 7 files changed, 238 insertions(+), 2 deletions(-) 14.7% src/backend/catalog/ 75.5% src/test/regress/expected/ 9.7% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..eb9e17fb727 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -752,6 +752,84 @@ SELECT (pg_identify_object(classid, objid, objsubid)).* type | create_property_graph_tests | g2 | create_property_graph_tests.g2 (21 rows) +-- test object address functions with recursive dependency walk +-- covers all property graph object types including indirect dependents +SELECT * +FROM ( + WITH RECURSIVE deps (classid, objid, objsubid, refclassid, refobjid, refobjsubid) AS ( + SELECT classid, objid, objsubid, + refclassid, refobjid, refobjsubid + FROM pg_depend + WHERE refclassid = 'pg_class'::regclass AND + refobjid = 'create_property_graph_tests.gt'::regclass + UNION ALL + SELECT d.classid, d.objid, d.objsubid, + d.refclassid, d.refobjid, d.refobjsubid + FROM pg_depend d + JOIN deps dp ON d.refclassid = dp.classid AND d.refobjid = dp.objid AND d.refobjsubid = dp.objsubid + ) + SELECT pg_describe_object(classid, objid, objsubid) as obj, + pg_identify_object(classid, objid, objsubid) as ident, + pg_identify_object_as_address(classid, objid, objsubid) as addr + FROM deps +) s +ORDER BY obj COLLATE "C", ident::text COLLATE "C"; + obj | ident | addr +----------------------------------------------------------+----------------------------------------------------------------------------+---------------------------------------------------------------------------- + edge e of property graph gt | ("property graph element",,,"e of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,e}",{}) + edge e of property graph gt | ("property graph element",,,"e of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,e}",{}) + edge e of property graph gt | ("property graph element",,,"e of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of property graph gt | ("property graph label",,,"e of create_property_graph_tests.gt") | ("property graph label","{create_property_graph_tests,gt,e}",{}) + label v1 of property graph gt | ("property graph label",,,"v1 of create_property_graph_tests.gt") | ("property graph label","{create_property_graph_tests,gt,v1}",{}) + label v1 of vertex v1 of property graph gt | ("property graph element label",,,"v1 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v1}",{}) + label v1 of vertex v1 of property graph gt | ("property graph element label",,,"v1 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v1}",{}) + label v2 of property graph gt | ("property graph label",,,"v2 of create_property_graph_tests.gt") | ("property graph label","{create_property_graph_tests,gt,v2}",{}) + label v2 of vertex v2 of property graph gt | ("property graph element label",,,"v2 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v2}",{}) + label v2 of vertex v2 of property graph gt | ("property graph element label",,,"v2 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v2}",{}) + property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property a of property graph gt | ("property graph property",,,"a of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,a}",{}) + property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property b of property graph gt | ("property graph property",,,"b of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,b}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of property graph gt | ("property graph property",,,"c of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,c}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of property graph gt | ("property graph property",,,"k1 of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,k1}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of property graph gt | ("property graph property",,,"k2 of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,k2}",{}) + property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property m of property graph gt | ("property graph property",,,"m of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,m}",{}) + property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property n of property graph gt | ("property graph property",,,"n of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,n}",{}) + type gt | (type,create_property_graph_tests,gt,create_property_graph_tests.gt) | (type,{create_property_graph_tests.gt},{}) + type gt[] | (type,create_property_graph_tests,_gt,create_property_graph_tests.gt[]) | (type,{create_property_graph_tests.gt[]},{}) + vertex v1 of property graph gt | ("property graph element",,,"v1 of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,v1}",{}) + vertex v2 of property graph gt | ("property graph element",,,"v2 of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,v2}",{}) +(52 rows) + \a\t SELECT pg_get_propgraphdef('g2'::regclass); CREATE PROPERTY GRAPH create_property_graph_tests.g2 diff --git a/src/test/regress/expected/event_trigger.out b/src/test/regress/expected/event_trigger.out index 065f586310f..ed8d5df397e 100644 --- a/src/test/regress/expected/event_trigger.out +++ b/src/test/regress/expected/event_trigger.out @@ -173,6 +173,23 @@ NOTICE: test_event_trigger: ddl_command_end CREATE USER MAPPING alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; NOTICE: test_event_trigger: ddl_command_end ALTER DEFAULT PRIVILEGES +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE TABLE t2x (i int PRIMARY KEY, j text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); +NOTICE: test_event_trigger: ddl_command_end CREATE PROPERTY GRAPH +DROP PROPERTY GRAPH gx; +NOTICE: test_event_trigger: ddl_command_end DROP PROPERTY GRAPH +DROP TABLE t1x, t2x; +NOTICE: test_event_trigger: ddl_command_end DROP TABLE -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; ERROR: permission denied to change owner of event trigger "regress_event_trigger" diff --git a/src/test/regress/expected/object_address.out b/src/test/regress/expected/object_address.out index 97227d67a54..5e53f0b092e 100644 --- a/src/test/regress/expected/object_address.out +++ b/src/test/regress/expected/object_address.out @@ -67,7 +67,9 @@ DECLARE BEGIN FOR objtype IN VALUES ('toast table'), ('index column'), ('sequence column'), ('toast table column'), ('view column'), ('materialized view column'), - ('property graph element'), ('property graph label'), ('property graph property') + ('property graph element'), ('property graph element label'), + ('property graph label'), ('property graph label property'), + ('property graph property') LOOP BEGIN PERFORM pg_get_object_address(objtype, '{one}', '{}'); @@ -84,7 +86,9 @@ WARNING: error for toast table column: unsupported object type "toast table col WARNING: error for view column: unsupported object type "view column" WARNING: error for materialized view column: unsupported object type "materialized view column" WARNING: error for property graph element: unsupported object type "property graph element" +WARNING: error for property graph element label: unrecognized object type "property graph element label" WARNING: error for property graph label: unsupported object type "property graph label" +WARNING: error for property graph label property: unrecognized object type "property graph label property" WARNING: error for property graph property: unsupported object type "property graph property" -- miscellaneous other errors select * from pg_get_object_address('operator of access method', '{btree,integer_ops,1}', '{int4,bool}'); @@ -593,7 +597,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace @@ -653,6 +659,8 @@ ORDER BY objects.classid, objects.objid, objects.objsubid; ("(""parameter ACL"",,,)")|("(""parameter ACL"",,)")|NULL ("(""property graph element"",,,)")|("(""property graph element"",,)")|NULL ("(""property graph label"",,,)")|("(""property graph label"",,)")|NULL +("(""property graph element label"",,,)")|("(""property graph element label"",,)")|NULL ("(""property graph property"",,,)")|("(""property graph property"",,)")|NULL +("(""property graph label property"",,,)")|("(""property graph label property"",,)")|NULL -- restore normal output mode \a\t diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..9608dd5c4af 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -298,6 +298,29 @@ SELECT (pg_identify_object(classid, objid, objsubid)).* refobjid = 'create_property_graph_tests.g2'::regclass ORDER BY 1, 2, 3, 4; +-- test object address functions with recursive dependency walk +-- covers all property graph object types including indirect dependents +SELECT * +FROM ( + WITH RECURSIVE deps (classid, objid, objsubid, refclassid, refobjid, refobjsubid) AS ( + SELECT classid, objid, objsubid, + refclassid, refobjid, refobjsubid + FROM pg_depend + WHERE refclassid = 'pg_class'::regclass AND + refobjid = 'create_property_graph_tests.gt'::regclass + UNION ALL + SELECT d.classid, d.objid, d.objsubid, + d.refclassid, d.refobjid, d.refobjsubid + FROM pg_depend d + JOIN deps dp ON d.refclassid = dp.classid AND d.refobjid = dp.objid AND d.refobjsubid = dp.objsubid + ) + SELECT pg_describe_object(classid, objid, objsubid) as obj, + pg_identify_object(classid, objid, objsubid) as ident, + pg_identify_object_as_address(classid, objid, objsubid) as addr + FROM deps +) s +ORDER BY obj COLLATE "C", ident::text COLLATE "C"; + \a\t SELECT pg_get_propgraphdef('g2'::regclass); SELECT pg_get_propgraphdef('g3'::regclass); diff --git a/src/test/regress/sql/event_trigger.sql b/src/test/regress/sql/event_trigger.sql index 32e9bb58c5e..271f443378b 100644 --- a/src/test/regress/sql/event_trigger.sql +++ b/src/test/regress/sql/event_trigger.sql @@ -143,6 +143,19 @@ create user mapping for regress_evt_user server useless_server; alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +CREATE TABLE t2x (i int PRIMARY KEY, j text); + +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); + +DROP PROPERTY GRAPH gx; +DROP TABLE t1x, t2x; + -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; diff --git a/src/test/regress/sql/object_address.sql b/src/test/regress/sql/object_address.sql index 1bbe9457c1c..27109d421c7 100644 --- a/src/test/regress/sql/object_address.sql +++ b/src/test/regress/sql/object_address.sql @@ -67,7 +67,9 @@ DECLARE BEGIN FOR objtype IN VALUES ('toast table'), ('index column'), ('sequence column'), ('toast table column'), ('view column'), ('materialized view column'), - ('property graph element'), ('property graph label'), ('property graph property') + ('property graph element'), ('property graph element label'), + ('property graph label'), ('property graph label property'), + ('property graph property') LOOP BEGIN PERFORM pg_get_object_address(objtype, '{one}', '{}'); @@ -282,7 +284,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace -- 2.34.1 --R84XrR4Hgw0dH3Ec-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v2] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-23 09:27 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-23 09:27 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing them to hit the default case and error out with "unsupported object class". During DROP PROPERTY GRAPH, this manifests when an event trigger is active, because pg_event_trigger_ddl_commands() calls these functions. The same code paths are also reachable via pg_identify_object() and pg_identify_object_as_address(). This commit adds the missing cases. Test coverage is added in object_address.sql for these two catalog types via the zero-OID test that exercises pg_identify_object() and pg_identify_object_as_address(). A test in event_trigger.sql verifies that DROP PROPERTY GRAPH works correctly when an event trigger is active. Author: Bertrand Drouvot <[email protected]> Reviewed-by: Michael Paquier <[email protected]> Reviewed-by: Ashutosh Bapat <[email protected]> Discussion: https://postgr.es/m/aej1DkLwhyZWmtxJ@bdtpg --- src/backend/catalog/objectaddress.c | 93 ++++++++++++++++++++ src/test/regress/expected/event_trigger.out | 17 ++++ src/test/regress/expected/object_address.out | 4 + src/test/regress/sql/event_trigger.sql | 13 +++ src/test/regress/sql/object_address.sql | 2 + 5 files changed, 129 insertions(+) 62.4% src/backend/catalog/ 25.6% src/test/regress/expected/ 11.8% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/event_trigger.out b/src/test/regress/expected/event_trigger.out index 065f586310f..ed8d5df397e 100644 --- a/src/test/regress/expected/event_trigger.out +++ b/src/test/regress/expected/event_trigger.out @@ -173,6 +173,23 @@ NOTICE: test_event_trigger: ddl_command_end CREATE USER MAPPING alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; NOTICE: test_event_trigger: ddl_command_end ALTER DEFAULT PRIVILEGES +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE TABLE t2x (i int PRIMARY KEY, j text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); +NOTICE: test_event_trigger: ddl_command_end CREATE PROPERTY GRAPH +DROP PROPERTY GRAPH gx; +NOTICE: test_event_trigger: ddl_command_end DROP PROPERTY GRAPH +DROP TABLE t1x, t2x; +NOTICE: test_event_trigger: ddl_command_end DROP TABLE -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; ERROR: permission denied to change owner of event trigger "regress_event_trigger" diff --git a/src/test/regress/expected/object_address.out b/src/test/regress/expected/object_address.out index 97227d67a54..729c3537f25 100644 --- a/src/test/regress/expected/object_address.out +++ b/src/test/regress/expected/object_address.out @@ -593,7 +593,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace @@ -653,6 +655,8 @@ ORDER BY objects.classid, objects.objid, objects.objsubid; ("(""parameter ACL"",,,)")|("(""parameter ACL"",,)")|NULL ("(""property graph element"",,,)")|("(""property graph element"",,)")|NULL ("(""property graph label"",,,)")|("(""property graph label"",,)")|NULL +("(""property graph element label"",,,)")|("(""property graph element label"",,)")|NULL ("(""property graph property"",,,)")|("(""property graph property"",,)")|NULL +("(""property graph label property"",,,)")|("(""property graph label property"",,)")|NULL -- restore normal output mode \a\t diff --git a/src/test/regress/sql/event_trigger.sql b/src/test/regress/sql/event_trigger.sql index 32e9bb58c5e..271f443378b 100644 --- a/src/test/regress/sql/event_trigger.sql +++ b/src/test/regress/sql/event_trigger.sql @@ -143,6 +143,19 @@ create user mapping for regress_evt_user server useless_server; alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +CREATE TABLE t2x (i int PRIMARY KEY, j text); + +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); + +DROP PROPERTY GRAPH gx; +DROP TABLE t1x, t2x; + -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; diff --git a/src/test/regress/sql/object_address.sql b/src/test/regress/sql/object_address.sql index 1bbe9457c1c..620dacf1045 100644 --- a/src/test/regress/sql/object_address.sql +++ b/src/test/regress/sql/object_address.sql @@ -282,7 +282,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace -- 2.34.1 --gtUR827Uq8d5gVsQ-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v3] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-23 09:27 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-23 09:27 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing them to hit the default case and error out with "unsupported object class". During DROP PROPERTY GRAPH, this manifests when an event trigger is active, because pg_event_trigger_ddl_commands() calls these functions. The same code paths are also reachable via pg_identify_object() and pg_identify_object_as_address(). This commit adds the missing cases. Test coverage is added in object_address.sql for these two catalog types and in create_property_graph.sql covering all property graph object types. A test in event_trigger.sql verifies that DROP PROPERTY GRAPH works correctly when an event trigger is active. Author: Bertrand Drouvot <[email protected]> Reviewed-by: Michael Paquier <[email protected]> Reviewed-by: Ashutosh Bapat <[email protected]> Discussion: https://postgr.es/m/aej1DkLwhyZWmtxJ@bdtpg --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 78 ++++++++++++++++ src/test/regress/expected/event_trigger.out | 17 ++++ src/test/regress/expected/object_address.out | 10 +- .../regress/sql/create_property_graph.sql | 23 +++++ src/test/regress/sql/event_trigger.sql | 13 +++ src/test/regress/sql/object_address.sql | 6 +- 7 files changed, 238 insertions(+), 2 deletions(-) 14.7% src/backend/catalog/ 75.5% src/test/regress/expected/ 9.7% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..eb9e17fb727 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -752,6 +752,84 @@ SELECT (pg_identify_object(classid, objid, objsubid)).* type | create_property_graph_tests | g2 | create_property_graph_tests.g2 (21 rows) +-- test object address functions with recursive dependency walk +-- covers all property graph object types including indirect dependents +SELECT * +FROM ( + WITH RECURSIVE deps (classid, objid, objsubid, refclassid, refobjid, refobjsubid) AS ( + SELECT classid, objid, objsubid, + refclassid, refobjid, refobjsubid + FROM pg_depend + WHERE refclassid = 'pg_class'::regclass AND + refobjid = 'create_property_graph_tests.gt'::regclass + UNION ALL + SELECT d.classid, d.objid, d.objsubid, + d.refclassid, d.refobjid, d.refobjsubid + FROM pg_depend d + JOIN deps dp ON d.refclassid = dp.classid AND d.refobjid = dp.objid AND d.refobjsubid = dp.objsubid + ) + SELECT pg_describe_object(classid, objid, objsubid) as obj, + pg_identify_object(classid, objid, objsubid) as ident, + pg_identify_object_as_address(classid, objid, objsubid) as addr + FROM deps +) s +ORDER BY obj COLLATE "C", ident::text COLLATE "C"; + obj | ident | addr +----------------------------------------------------------+----------------------------------------------------------------------------+---------------------------------------------------------------------------- + edge e of property graph gt | ("property graph element",,,"e of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,e}",{}) + edge e of property graph gt | ("property graph element",,,"e of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,e}",{}) + edge e of property graph gt | ("property graph element",,,"e of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of property graph gt | ("property graph label",,,"e of create_property_graph_tests.gt") | ("property graph label","{create_property_graph_tests,gt,e}",{}) + label v1 of property graph gt | ("property graph label",,,"v1 of create_property_graph_tests.gt") | ("property graph label","{create_property_graph_tests,gt,v1}",{}) + label v1 of vertex v1 of property graph gt | ("property graph element label",,,"v1 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v1}",{}) + label v1 of vertex v1 of property graph gt | ("property graph element label",,,"v1 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v1}",{}) + label v2 of property graph gt | ("property graph label",,,"v2 of create_property_graph_tests.gt") | ("property graph label","{create_property_graph_tests,gt,v2}",{}) + label v2 of vertex v2 of property graph gt | ("property graph element label",,,"v2 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v2}",{}) + label v2 of vertex v2 of property graph gt | ("property graph element label",,,"v2 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v2}",{}) + property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property a of property graph gt | ("property graph property",,,"a of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,a}",{}) + property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property b of property graph gt | ("property graph property",,,"b of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,b}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of property graph gt | ("property graph property",,,"c of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,c}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of property graph gt | ("property graph property",,,"k1 of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,k1}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of property graph gt | ("property graph property",,,"k2 of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,k2}",{}) + property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property m of property graph gt | ("property graph property",,,"m of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,m}",{}) + property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property n of property graph gt | ("property graph property",,,"n of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,n}",{}) + type gt | (type,create_property_graph_tests,gt,create_property_graph_tests.gt) | (type,{create_property_graph_tests.gt},{}) + type gt[] | (type,create_property_graph_tests,_gt,create_property_graph_tests.gt[]) | (type,{create_property_graph_tests.gt[]},{}) + vertex v1 of property graph gt | ("property graph element",,,"v1 of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,v1}",{}) + vertex v2 of property graph gt | ("property graph element",,,"v2 of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,v2}",{}) +(52 rows) + \a\t SELECT pg_get_propgraphdef('g2'::regclass); CREATE PROPERTY GRAPH create_property_graph_tests.g2 diff --git a/src/test/regress/expected/event_trigger.out b/src/test/regress/expected/event_trigger.out index 065f586310f..ed8d5df397e 100644 --- a/src/test/regress/expected/event_trigger.out +++ b/src/test/regress/expected/event_trigger.out @@ -173,6 +173,23 @@ NOTICE: test_event_trigger: ddl_command_end CREATE USER MAPPING alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; NOTICE: test_event_trigger: ddl_command_end ALTER DEFAULT PRIVILEGES +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE TABLE t2x (i int PRIMARY KEY, j text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); +NOTICE: test_event_trigger: ddl_command_end CREATE PROPERTY GRAPH +DROP PROPERTY GRAPH gx; +NOTICE: test_event_trigger: ddl_command_end DROP PROPERTY GRAPH +DROP TABLE t1x, t2x; +NOTICE: test_event_trigger: ddl_command_end DROP TABLE -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; ERROR: permission denied to change owner of event trigger "regress_event_trigger" diff --git a/src/test/regress/expected/object_address.out b/src/test/regress/expected/object_address.out index 97227d67a54..5e53f0b092e 100644 --- a/src/test/regress/expected/object_address.out +++ b/src/test/regress/expected/object_address.out @@ -67,7 +67,9 @@ DECLARE BEGIN FOR objtype IN VALUES ('toast table'), ('index column'), ('sequence column'), ('toast table column'), ('view column'), ('materialized view column'), - ('property graph element'), ('property graph label'), ('property graph property') + ('property graph element'), ('property graph element label'), + ('property graph label'), ('property graph label property'), + ('property graph property') LOOP BEGIN PERFORM pg_get_object_address(objtype, '{one}', '{}'); @@ -84,7 +86,9 @@ WARNING: error for toast table column: unsupported object type "toast table col WARNING: error for view column: unsupported object type "view column" WARNING: error for materialized view column: unsupported object type "materialized view column" WARNING: error for property graph element: unsupported object type "property graph element" +WARNING: error for property graph element label: unrecognized object type "property graph element label" WARNING: error for property graph label: unsupported object type "property graph label" +WARNING: error for property graph label property: unrecognized object type "property graph label property" WARNING: error for property graph property: unsupported object type "property graph property" -- miscellaneous other errors select * from pg_get_object_address('operator of access method', '{btree,integer_ops,1}', '{int4,bool}'); @@ -593,7 +597,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace @@ -653,6 +659,8 @@ ORDER BY objects.classid, objects.objid, objects.objsubid; ("(""parameter ACL"",,,)")|("(""parameter ACL"",,)")|NULL ("(""property graph element"",,,)")|("(""property graph element"",,)")|NULL ("(""property graph label"",,,)")|("(""property graph label"",,)")|NULL +("(""property graph element label"",,,)")|("(""property graph element label"",,)")|NULL ("(""property graph property"",,,)")|("(""property graph property"",,)")|NULL +("(""property graph label property"",,,)")|("(""property graph label property"",,)")|NULL -- restore normal output mode \a\t diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..9608dd5c4af 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -298,6 +298,29 @@ SELECT (pg_identify_object(classid, objid, objsubid)).* refobjid = 'create_property_graph_tests.g2'::regclass ORDER BY 1, 2, 3, 4; +-- test object address functions with recursive dependency walk +-- covers all property graph object types including indirect dependents +SELECT * +FROM ( + WITH RECURSIVE deps (classid, objid, objsubid, refclassid, refobjid, refobjsubid) AS ( + SELECT classid, objid, objsubid, + refclassid, refobjid, refobjsubid + FROM pg_depend + WHERE refclassid = 'pg_class'::regclass AND + refobjid = 'create_property_graph_tests.gt'::regclass + UNION ALL + SELECT d.classid, d.objid, d.objsubid, + d.refclassid, d.refobjid, d.refobjsubid + FROM pg_depend d + JOIN deps dp ON d.refclassid = dp.classid AND d.refobjid = dp.objid AND d.refobjsubid = dp.objsubid + ) + SELECT pg_describe_object(classid, objid, objsubid) as obj, + pg_identify_object(classid, objid, objsubid) as ident, + pg_identify_object_as_address(classid, objid, objsubid) as addr + FROM deps +) s +ORDER BY obj COLLATE "C", ident::text COLLATE "C"; + \a\t SELECT pg_get_propgraphdef('g2'::regclass); SELECT pg_get_propgraphdef('g3'::regclass); diff --git a/src/test/regress/sql/event_trigger.sql b/src/test/regress/sql/event_trigger.sql index 32e9bb58c5e..271f443378b 100644 --- a/src/test/regress/sql/event_trigger.sql +++ b/src/test/regress/sql/event_trigger.sql @@ -143,6 +143,19 @@ create user mapping for regress_evt_user server useless_server; alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +CREATE TABLE t2x (i int PRIMARY KEY, j text); + +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); + +DROP PROPERTY GRAPH gx; +DROP TABLE t1x, t2x; + -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; diff --git a/src/test/regress/sql/object_address.sql b/src/test/regress/sql/object_address.sql index 1bbe9457c1c..27109d421c7 100644 --- a/src/test/regress/sql/object_address.sql +++ b/src/test/regress/sql/object_address.sql @@ -67,7 +67,9 @@ DECLARE BEGIN FOR objtype IN VALUES ('toast table'), ('index column'), ('sequence column'), ('toast table column'), ('view column'), ('materialized view column'), - ('property graph element'), ('property graph label'), ('property graph property') + ('property graph element'), ('property graph element label'), + ('property graph label'), ('property graph label property'), + ('property graph property') LOOP BEGIN PERFORM pg_get_object_address(objtype, '{one}', '{}'); @@ -282,7 +284,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace -- 2.34.1 --R84XrR4Hgw0dH3Ec-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v2] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-23 09:27 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-23 09:27 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing them to hit the default case and error out with "unsupported object class". During DROP PROPERTY GRAPH, this manifests when an event trigger is active, because pg_event_trigger_ddl_commands() calls these functions. The same code paths are also reachable via pg_identify_object() and pg_identify_object_as_address(). This commit adds the missing cases. Test coverage is added in object_address.sql for these two catalog types via the zero-OID test that exercises pg_identify_object() and pg_identify_object_as_address(). A test in event_trigger.sql verifies that DROP PROPERTY GRAPH works correctly when an event trigger is active. Author: Bertrand Drouvot <[email protected]> Reviewed-by: Michael Paquier <[email protected]> Reviewed-by: Ashutosh Bapat <[email protected]> Discussion: https://postgr.es/m/aej1DkLwhyZWmtxJ@bdtpg --- src/backend/catalog/objectaddress.c | 93 ++++++++++++++++++++ src/test/regress/expected/event_trigger.out | 17 ++++ src/test/regress/expected/object_address.out | 4 + src/test/regress/sql/event_trigger.sql | 13 +++ src/test/regress/sql/object_address.sql | 2 + 5 files changed, 129 insertions(+) 62.4% src/backend/catalog/ 25.6% src/test/regress/expected/ 11.8% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/event_trigger.out b/src/test/regress/expected/event_trigger.out index 065f586310f..ed8d5df397e 100644 --- a/src/test/regress/expected/event_trigger.out +++ b/src/test/regress/expected/event_trigger.out @@ -173,6 +173,23 @@ NOTICE: test_event_trigger: ddl_command_end CREATE USER MAPPING alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; NOTICE: test_event_trigger: ddl_command_end ALTER DEFAULT PRIVILEGES +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE TABLE t2x (i int PRIMARY KEY, j text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); +NOTICE: test_event_trigger: ddl_command_end CREATE PROPERTY GRAPH +DROP PROPERTY GRAPH gx; +NOTICE: test_event_trigger: ddl_command_end DROP PROPERTY GRAPH +DROP TABLE t1x, t2x; +NOTICE: test_event_trigger: ddl_command_end DROP TABLE -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; ERROR: permission denied to change owner of event trigger "regress_event_trigger" diff --git a/src/test/regress/expected/object_address.out b/src/test/regress/expected/object_address.out index 97227d67a54..729c3537f25 100644 --- a/src/test/regress/expected/object_address.out +++ b/src/test/regress/expected/object_address.out @@ -593,7 +593,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace @@ -653,6 +655,8 @@ ORDER BY objects.classid, objects.objid, objects.objsubid; ("(""parameter ACL"",,,)")|("(""parameter ACL"",,)")|NULL ("(""property graph element"",,,)")|("(""property graph element"",,)")|NULL ("(""property graph label"",,,)")|("(""property graph label"",,)")|NULL +("(""property graph element label"",,,)")|("(""property graph element label"",,)")|NULL ("(""property graph property"",,,)")|("(""property graph property"",,)")|NULL +("(""property graph label property"",,,)")|("(""property graph label property"",,)")|NULL -- restore normal output mode \a\t diff --git a/src/test/regress/sql/event_trigger.sql b/src/test/regress/sql/event_trigger.sql index 32e9bb58c5e..271f443378b 100644 --- a/src/test/regress/sql/event_trigger.sql +++ b/src/test/regress/sql/event_trigger.sql @@ -143,6 +143,19 @@ create user mapping for regress_evt_user server useless_server; alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +CREATE TABLE t2x (i int PRIMARY KEY, j text); + +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); + +DROP PROPERTY GRAPH gx; +DROP TABLE t1x, t2x; + -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; diff --git a/src/test/regress/sql/object_address.sql b/src/test/regress/sql/object_address.sql index 1bbe9457c1c..620dacf1045 100644 --- a/src/test/regress/sql/object_address.sql +++ b/src/test/regress/sql/object_address.sql @@ -282,7 +282,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace -- 2.34.1 --gtUR827Uq8d5gVsQ-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v2] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-23 09:27 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-23 09:27 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing them to hit the default case and error out with "unsupported object class". During DROP PROPERTY GRAPH, this manifests when an event trigger is active, because pg_event_trigger_ddl_commands() calls these functions. The same code paths are also reachable via pg_identify_object() and pg_identify_object_as_address(). This commit adds the missing cases. Test coverage is added in object_address.sql for these two catalog types via the zero-OID test that exercises pg_identify_object() and pg_identify_object_as_address(). A test in event_trigger.sql verifies that DROP PROPERTY GRAPH works correctly when an event trigger is active. Author: Bertrand Drouvot <[email protected]> Reviewed-by: Michael Paquier <[email protected]> Reviewed-by: Ashutosh Bapat <[email protected]> Discussion: https://postgr.es/m/aej1DkLwhyZWmtxJ@bdtpg --- src/backend/catalog/objectaddress.c | 93 ++++++++++++++++++++ src/test/regress/expected/event_trigger.out | 17 ++++ src/test/regress/expected/object_address.out | 4 + src/test/regress/sql/event_trigger.sql | 13 +++ src/test/regress/sql/object_address.sql | 2 + 5 files changed, 129 insertions(+) 62.4% src/backend/catalog/ 25.6% src/test/regress/expected/ 11.8% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/event_trigger.out b/src/test/regress/expected/event_trigger.out index 065f586310f..ed8d5df397e 100644 --- a/src/test/regress/expected/event_trigger.out +++ b/src/test/regress/expected/event_trigger.out @@ -173,6 +173,23 @@ NOTICE: test_event_trigger: ddl_command_end CREATE USER MAPPING alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; NOTICE: test_event_trigger: ddl_command_end ALTER DEFAULT PRIVILEGES +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE TABLE t2x (i int PRIMARY KEY, j text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); +NOTICE: test_event_trigger: ddl_command_end CREATE PROPERTY GRAPH +DROP PROPERTY GRAPH gx; +NOTICE: test_event_trigger: ddl_command_end DROP PROPERTY GRAPH +DROP TABLE t1x, t2x; +NOTICE: test_event_trigger: ddl_command_end DROP TABLE -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; ERROR: permission denied to change owner of event trigger "regress_event_trigger" diff --git a/src/test/regress/expected/object_address.out b/src/test/regress/expected/object_address.out index 97227d67a54..729c3537f25 100644 --- a/src/test/regress/expected/object_address.out +++ b/src/test/regress/expected/object_address.out @@ -593,7 +593,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace @@ -653,6 +655,8 @@ ORDER BY objects.classid, objects.objid, objects.objsubid; ("(""parameter ACL"",,,)")|("(""parameter ACL"",,)")|NULL ("(""property graph element"",,,)")|("(""property graph element"",,)")|NULL ("(""property graph label"",,,)")|("(""property graph label"",,)")|NULL +("(""property graph element label"",,,)")|("(""property graph element label"",,)")|NULL ("(""property graph property"",,,)")|("(""property graph property"",,)")|NULL +("(""property graph label property"",,,)")|("(""property graph label property"",,)")|NULL -- restore normal output mode \a\t diff --git a/src/test/regress/sql/event_trigger.sql b/src/test/regress/sql/event_trigger.sql index 32e9bb58c5e..271f443378b 100644 --- a/src/test/regress/sql/event_trigger.sql +++ b/src/test/regress/sql/event_trigger.sql @@ -143,6 +143,19 @@ create user mapping for regress_evt_user server useless_server; alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +CREATE TABLE t2x (i int PRIMARY KEY, j text); + +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); + +DROP PROPERTY GRAPH gx; +DROP TABLE t1x, t2x; + -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; diff --git a/src/test/regress/sql/object_address.sql b/src/test/regress/sql/object_address.sql index 1bbe9457c1c..620dacf1045 100644 --- a/src/test/regress/sql/object_address.sql +++ b/src/test/regress/sql/object_address.sql @@ -282,7 +282,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace -- 2.34.1 --gtUR827Uq8d5gVsQ-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v3] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-23 09:27 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-23 09:27 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing them to hit the default case and error out with "unsupported object class". During DROP PROPERTY GRAPH, this manifests when an event trigger is active, because pg_event_trigger_ddl_commands() calls these functions. The same code paths are also reachable via pg_identify_object() and pg_identify_object_as_address(). This commit adds the missing cases. Test coverage is added in object_address.sql for these two catalog types and in create_property_graph.sql covering all property graph object types. A test in event_trigger.sql verifies that DROP PROPERTY GRAPH works correctly when an event trigger is active. Author: Bertrand Drouvot <[email protected]> Reviewed-by: Michael Paquier <[email protected]> Reviewed-by: Ashutosh Bapat <[email protected]> Discussion: https://postgr.es/m/aej1DkLwhyZWmtxJ@bdtpg --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 78 ++++++++++++++++ src/test/regress/expected/event_trigger.out | 17 ++++ src/test/regress/expected/object_address.out | 10 +- .../regress/sql/create_property_graph.sql | 23 +++++ src/test/regress/sql/event_trigger.sql | 13 +++ src/test/regress/sql/object_address.sql | 6 +- 7 files changed, 238 insertions(+), 2 deletions(-) 14.7% src/backend/catalog/ 75.5% src/test/regress/expected/ 9.7% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..eb9e17fb727 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -752,6 +752,84 @@ SELECT (pg_identify_object(classid, objid, objsubid)).* type | create_property_graph_tests | g2 | create_property_graph_tests.g2 (21 rows) +-- test object address functions with recursive dependency walk +-- covers all property graph object types including indirect dependents +SELECT * +FROM ( + WITH RECURSIVE deps (classid, objid, objsubid, refclassid, refobjid, refobjsubid) AS ( + SELECT classid, objid, objsubid, + refclassid, refobjid, refobjsubid + FROM pg_depend + WHERE refclassid = 'pg_class'::regclass AND + refobjid = 'create_property_graph_tests.gt'::regclass + UNION ALL + SELECT d.classid, d.objid, d.objsubid, + d.refclassid, d.refobjid, d.refobjsubid + FROM pg_depend d + JOIN deps dp ON d.refclassid = dp.classid AND d.refobjid = dp.objid AND d.refobjsubid = dp.objsubid + ) + SELECT pg_describe_object(classid, objid, objsubid) as obj, + pg_identify_object(classid, objid, objsubid) as ident, + pg_identify_object_as_address(classid, objid, objsubid) as addr + FROM deps +) s +ORDER BY obj COLLATE "C", ident::text COLLATE "C"; + obj | ident | addr +----------------------------------------------------------+----------------------------------------------------------------------------+---------------------------------------------------------------------------- + edge e of property graph gt | ("property graph element",,,"e of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,e}",{}) + edge e of property graph gt | ("property graph element",,,"e of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,e}",{}) + edge e of property graph gt | ("property graph element",,,"e of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of property graph gt | ("property graph label",,,"e of create_property_graph_tests.gt") | ("property graph label","{create_property_graph_tests,gt,e}",{}) + label v1 of property graph gt | ("property graph label",,,"v1 of create_property_graph_tests.gt") | ("property graph label","{create_property_graph_tests,gt,v1}",{}) + label v1 of vertex v1 of property graph gt | ("property graph element label",,,"v1 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v1}",{}) + label v1 of vertex v1 of property graph gt | ("property graph element label",,,"v1 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v1}",{}) + label v2 of property graph gt | ("property graph label",,,"v2 of create_property_graph_tests.gt") | ("property graph label","{create_property_graph_tests,gt,v2}",{}) + label v2 of vertex v2 of property graph gt | ("property graph element label",,,"v2 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v2}",{}) + label v2 of vertex v2 of property graph gt | ("property graph element label",,,"v2 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v2}",{}) + property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property a of property graph gt | ("property graph property",,,"a of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,a}",{}) + property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property b of property graph gt | ("property graph property",,,"b of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,b}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of property graph gt | ("property graph property",,,"c of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,c}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of property graph gt | ("property graph property",,,"k1 of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,k1}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of property graph gt | ("property graph property",,,"k2 of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,k2}",{}) + property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property m of property graph gt | ("property graph property",,,"m of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,m}",{}) + property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property n of property graph gt | ("property graph property",,,"n of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,n}",{}) + type gt | (type,create_property_graph_tests,gt,create_property_graph_tests.gt) | (type,{create_property_graph_tests.gt},{}) + type gt[] | (type,create_property_graph_tests,_gt,create_property_graph_tests.gt[]) | (type,{create_property_graph_tests.gt[]},{}) + vertex v1 of property graph gt | ("property graph element",,,"v1 of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,v1}",{}) + vertex v2 of property graph gt | ("property graph element",,,"v2 of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,v2}",{}) +(52 rows) + \a\t SELECT pg_get_propgraphdef('g2'::regclass); CREATE PROPERTY GRAPH create_property_graph_tests.g2 diff --git a/src/test/regress/expected/event_trigger.out b/src/test/regress/expected/event_trigger.out index 065f586310f..ed8d5df397e 100644 --- a/src/test/regress/expected/event_trigger.out +++ b/src/test/regress/expected/event_trigger.out @@ -173,6 +173,23 @@ NOTICE: test_event_trigger: ddl_command_end CREATE USER MAPPING alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; NOTICE: test_event_trigger: ddl_command_end ALTER DEFAULT PRIVILEGES +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE TABLE t2x (i int PRIMARY KEY, j text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); +NOTICE: test_event_trigger: ddl_command_end CREATE PROPERTY GRAPH +DROP PROPERTY GRAPH gx; +NOTICE: test_event_trigger: ddl_command_end DROP PROPERTY GRAPH +DROP TABLE t1x, t2x; +NOTICE: test_event_trigger: ddl_command_end DROP TABLE -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; ERROR: permission denied to change owner of event trigger "regress_event_trigger" diff --git a/src/test/regress/expected/object_address.out b/src/test/regress/expected/object_address.out index 97227d67a54..5e53f0b092e 100644 --- a/src/test/regress/expected/object_address.out +++ b/src/test/regress/expected/object_address.out @@ -67,7 +67,9 @@ DECLARE BEGIN FOR objtype IN VALUES ('toast table'), ('index column'), ('sequence column'), ('toast table column'), ('view column'), ('materialized view column'), - ('property graph element'), ('property graph label'), ('property graph property') + ('property graph element'), ('property graph element label'), + ('property graph label'), ('property graph label property'), + ('property graph property') LOOP BEGIN PERFORM pg_get_object_address(objtype, '{one}', '{}'); @@ -84,7 +86,9 @@ WARNING: error for toast table column: unsupported object type "toast table col WARNING: error for view column: unsupported object type "view column" WARNING: error for materialized view column: unsupported object type "materialized view column" WARNING: error for property graph element: unsupported object type "property graph element" +WARNING: error for property graph element label: unrecognized object type "property graph element label" WARNING: error for property graph label: unsupported object type "property graph label" +WARNING: error for property graph label property: unrecognized object type "property graph label property" WARNING: error for property graph property: unsupported object type "property graph property" -- miscellaneous other errors select * from pg_get_object_address('operator of access method', '{btree,integer_ops,1}', '{int4,bool}'); @@ -593,7 +597,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace @@ -653,6 +659,8 @@ ORDER BY objects.classid, objects.objid, objects.objsubid; ("(""parameter ACL"",,,)")|("(""parameter ACL"",,)")|NULL ("(""property graph element"",,,)")|("(""property graph element"",,)")|NULL ("(""property graph label"",,,)")|("(""property graph label"",,)")|NULL +("(""property graph element label"",,,)")|("(""property graph element label"",,)")|NULL ("(""property graph property"",,,)")|("(""property graph property"",,)")|NULL +("(""property graph label property"",,,)")|("(""property graph label property"",,)")|NULL -- restore normal output mode \a\t diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..9608dd5c4af 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -298,6 +298,29 @@ SELECT (pg_identify_object(classid, objid, objsubid)).* refobjid = 'create_property_graph_tests.g2'::regclass ORDER BY 1, 2, 3, 4; +-- test object address functions with recursive dependency walk +-- covers all property graph object types including indirect dependents +SELECT * +FROM ( + WITH RECURSIVE deps (classid, objid, objsubid, refclassid, refobjid, refobjsubid) AS ( + SELECT classid, objid, objsubid, + refclassid, refobjid, refobjsubid + FROM pg_depend + WHERE refclassid = 'pg_class'::regclass AND + refobjid = 'create_property_graph_tests.gt'::regclass + UNION ALL + SELECT d.classid, d.objid, d.objsubid, + d.refclassid, d.refobjid, d.refobjsubid + FROM pg_depend d + JOIN deps dp ON d.refclassid = dp.classid AND d.refobjid = dp.objid AND d.refobjsubid = dp.objsubid + ) + SELECT pg_describe_object(classid, objid, objsubid) as obj, + pg_identify_object(classid, objid, objsubid) as ident, + pg_identify_object_as_address(classid, objid, objsubid) as addr + FROM deps +) s +ORDER BY obj COLLATE "C", ident::text COLLATE "C"; + \a\t SELECT pg_get_propgraphdef('g2'::regclass); SELECT pg_get_propgraphdef('g3'::regclass); diff --git a/src/test/regress/sql/event_trigger.sql b/src/test/regress/sql/event_trigger.sql index 32e9bb58c5e..271f443378b 100644 --- a/src/test/regress/sql/event_trigger.sql +++ b/src/test/regress/sql/event_trigger.sql @@ -143,6 +143,19 @@ create user mapping for regress_evt_user server useless_server; alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +CREATE TABLE t2x (i int PRIMARY KEY, j text); + +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); + +DROP PROPERTY GRAPH gx; +DROP TABLE t1x, t2x; + -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; diff --git a/src/test/regress/sql/object_address.sql b/src/test/regress/sql/object_address.sql index 1bbe9457c1c..27109d421c7 100644 --- a/src/test/regress/sql/object_address.sql +++ b/src/test/regress/sql/object_address.sql @@ -67,7 +67,9 @@ DECLARE BEGIN FOR objtype IN VALUES ('toast table'), ('index column'), ('sequence column'), ('toast table column'), ('view column'), ('materialized view column'), - ('property graph element'), ('property graph label'), ('property graph property') + ('property graph element'), ('property graph element label'), + ('property graph label'), ('property graph label property'), + ('property graph property') LOOP BEGIN PERFORM pg_get_object_address(objtype, '{one}', '{}'); @@ -282,7 +284,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace -- 2.34.1 --R84XrR4Hgw0dH3Ec-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v2] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-23 09:27 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-23 09:27 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing them to hit the default case and error out with "unsupported object class". During DROP PROPERTY GRAPH, this manifests when an event trigger is active, because pg_event_trigger_ddl_commands() calls these functions. The same code paths are also reachable via pg_identify_object() and pg_identify_object_as_address(). This commit adds the missing cases. Test coverage is added in object_address.sql for these two catalog types via the zero-OID test that exercises pg_identify_object() and pg_identify_object_as_address(). A test in event_trigger.sql verifies that DROP PROPERTY GRAPH works correctly when an event trigger is active. Author: Bertrand Drouvot <[email protected]> Reviewed-by: Michael Paquier <[email protected]> Reviewed-by: Ashutosh Bapat <[email protected]> Discussion: https://postgr.es/m/aej1DkLwhyZWmtxJ@bdtpg --- src/backend/catalog/objectaddress.c | 93 ++++++++++++++++++++ src/test/regress/expected/event_trigger.out | 17 ++++ src/test/regress/expected/object_address.out | 4 + src/test/regress/sql/event_trigger.sql | 13 +++ src/test/regress/sql/object_address.sql | 2 + 5 files changed, 129 insertions(+) 62.4% src/backend/catalog/ 25.6% src/test/regress/expected/ 11.8% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/event_trigger.out b/src/test/regress/expected/event_trigger.out index 065f586310f..ed8d5df397e 100644 --- a/src/test/regress/expected/event_trigger.out +++ b/src/test/regress/expected/event_trigger.out @@ -173,6 +173,23 @@ NOTICE: test_event_trigger: ddl_command_end CREATE USER MAPPING alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; NOTICE: test_event_trigger: ddl_command_end ALTER DEFAULT PRIVILEGES +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE TABLE t2x (i int PRIMARY KEY, j text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); +NOTICE: test_event_trigger: ddl_command_end CREATE PROPERTY GRAPH +DROP PROPERTY GRAPH gx; +NOTICE: test_event_trigger: ddl_command_end DROP PROPERTY GRAPH +DROP TABLE t1x, t2x; +NOTICE: test_event_trigger: ddl_command_end DROP TABLE -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; ERROR: permission denied to change owner of event trigger "regress_event_trigger" diff --git a/src/test/regress/expected/object_address.out b/src/test/regress/expected/object_address.out index 97227d67a54..729c3537f25 100644 --- a/src/test/regress/expected/object_address.out +++ b/src/test/regress/expected/object_address.out @@ -593,7 +593,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace @@ -653,6 +655,8 @@ ORDER BY objects.classid, objects.objid, objects.objsubid; ("(""parameter ACL"",,,)")|("(""parameter ACL"",,)")|NULL ("(""property graph element"",,,)")|("(""property graph element"",,)")|NULL ("(""property graph label"",,,)")|("(""property graph label"",,)")|NULL +("(""property graph element label"",,,)")|("(""property graph element label"",,)")|NULL ("(""property graph property"",,,)")|("(""property graph property"",,)")|NULL +("(""property graph label property"",,,)")|("(""property graph label property"",,)")|NULL -- restore normal output mode \a\t diff --git a/src/test/regress/sql/event_trigger.sql b/src/test/regress/sql/event_trigger.sql index 32e9bb58c5e..271f443378b 100644 --- a/src/test/regress/sql/event_trigger.sql +++ b/src/test/regress/sql/event_trigger.sql @@ -143,6 +143,19 @@ create user mapping for regress_evt_user server useless_server; alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +CREATE TABLE t2x (i int PRIMARY KEY, j text); + +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); + +DROP PROPERTY GRAPH gx; +DROP TABLE t1x, t2x; + -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; diff --git a/src/test/regress/sql/object_address.sql b/src/test/regress/sql/object_address.sql index 1bbe9457c1c..620dacf1045 100644 --- a/src/test/regress/sql/object_address.sql +++ b/src/test/regress/sql/object_address.sql @@ -282,7 +282,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace -- 2.34.1 --gtUR827Uq8d5gVsQ-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v3] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-23 09:27 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-23 09:27 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing them to hit the default case and error out with "unsupported object class". During DROP PROPERTY GRAPH, this manifests when an event trigger is active, because pg_event_trigger_ddl_commands() calls these functions. The same code paths are also reachable via pg_identify_object() and pg_identify_object_as_address(). This commit adds the missing cases. Test coverage is added in object_address.sql for these two catalog types and in create_property_graph.sql covering all property graph object types. A test in event_trigger.sql verifies that DROP PROPERTY GRAPH works correctly when an event trigger is active. Author: Bertrand Drouvot <[email protected]> Reviewed-by: Michael Paquier <[email protected]> Reviewed-by: Ashutosh Bapat <[email protected]> Discussion: https://postgr.es/m/aej1DkLwhyZWmtxJ@bdtpg --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 78 ++++++++++++++++ src/test/regress/expected/event_trigger.out | 17 ++++ src/test/regress/expected/object_address.out | 10 +- .../regress/sql/create_property_graph.sql | 23 +++++ src/test/regress/sql/event_trigger.sql | 13 +++ src/test/regress/sql/object_address.sql | 6 +- 7 files changed, 238 insertions(+), 2 deletions(-) 14.7% src/backend/catalog/ 75.5% src/test/regress/expected/ 9.7% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..eb9e17fb727 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -752,6 +752,84 @@ SELECT (pg_identify_object(classid, objid, objsubid)).* type | create_property_graph_tests | g2 | create_property_graph_tests.g2 (21 rows) +-- test object address functions with recursive dependency walk +-- covers all property graph object types including indirect dependents +SELECT * +FROM ( + WITH RECURSIVE deps (classid, objid, objsubid, refclassid, refobjid, refobjsubid) AS ( + SELECT classid, objid, objsubid, + refclassid, refobjid, refobjsubid + FROM pg_depend + WHERE refclassid = 'pg_class'::regclass AND + refobjid = 'create_property_graph_tests.gt'::regclass + UNION ALL + SELECT d.classid, d.objid, d.objsubid, + d.refclassid, d.refobjid, d.refobjsubid + FROM pg_depend d + JOIN deps dp ON d.refclassid = dp.classid AND d.refobjid = dp.objid AND d.refobjsubid = dp.objsubid + ) + SELECT pg_describe_object(classid, objid, objsubid) as obj, + pg_identify_object(classid, objid, objsubid) as ident, + pg_identify_object_as_address(classid, objid, objsubid) as addr + FROM deps +) s +ORDER BY obj COLLATE "C", ident::text COLLATE "C"; + obj | ident | addr +----------------------------------------------------------+----------------------------------------------------------------------------+---------------------------------------------------------------------------- + edge e of property graph gt | ("property graph element",,,"e of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,e}",{}) + edge e of property graph gt | ("property graph element",,,"e of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,e}",{}) + edge e of property graph gt | ("property graph element",,,"e of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of property graph gt | ("property graph label",,,"e of create_property_graph_tests.gt") | ("property graph label","{create_property_graph_tests,gt,e}",{}) + label v1 of property graph gt | ("property graph label",,,"v1 of create_property_graph_tests.gt") | ("property graph label","{create_property_graph_tests,gt,v1}",{}) + label v1 of vertex v1 of property graph gt | ("property graph element label",,,"v1 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v1}",{}) + label v1 of vertex v1 of property graph gt | ("property graph element label",,,"v1 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v1}",{}) + label v2 of property graph gt | ("property graph label",,,"v2 of create_property_graph_tests.gt") | ("property graph label","{create_property_graph_tests,gt,v2}",{}) + label v2 of vertex v2 of property graph gt | ("property graph element label",,,"v2 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v2}",{}) + label v2 of vertex v2 of property graph gt | ("property graph element label",,,"v2 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v2}",{}) + property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property a of property graph gt | ("property graph property",,,"a of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,a}",{}) + property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property b of property graph gt | ("property graph property",,,"b of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,b}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of property graph gt | ("property graph property",,,"c of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,c}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of property graph gt | ("property graph property",,,"k1 of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,k1}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of property graph gt | ("property graph property",,,"k2 of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,k2}",{}) + property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property m of property graph gt | ("property graph property",,,"m of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,m}",{}) + property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property n of property graph gt | ("property graph property",,,"n of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,n}",{}) + type gt | (type,create_property_graph_tests,gt,create_property_graph_tests.gt) | (type,{create_property_graph_tests.gt},{}) + type gt[] | (type,create_property_graph_tests,_gt,create_property_graph_tests.gt[]) | (type,{create_property_graph_tests.gt[]},{}) + vertex v1 of property graph gt | ("property graph element",,,"v1 of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,v1}",{}) + vertex v2 of property graph gt | ("property graph element",,,"v2 of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,v2}",{}) +(52 rows) + \a\t SELECT pg_get_propgraphdef('g2'::regclass); CREATE PROPERTY GRAPH create_property_graph_tests.g2 diff --git a/src/test/regress/expected/event_trigger.out b/src/test/regress/expected/event_trigger.out index 065f586310f..ed8d5df397e 100644 --- a/src/test/regress/expected/event_trigger.out +++ b/src/test/regress/expected/event_trigger.out @@ -173,6 +173,23 @@ NOTICE: test_event_trigger: ddl_command_end CREATE USER MAPPING alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; NOTICE: test_event_trigger: ddl_command_end ALTER DEFAULT PRIVILEGES +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE TABLE t2x (i int PRIMARY KEY, j text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); +NOTICE: test_event_trigger: ddl_command_end CREATE PROPERTY GRAPH +DROP PROPERTY GRAPH gx; +NOTICE: test_event_trigger: ddl_command_end DROP PROPERTY GRAPH +DROP TABLE t1x, t2x; +NOTICE: test_event_trigger: ddl_command_end DROP TABLE -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; ERROR: permission denied to change owner of event trigger "regress_event_trigger" diff --git a/src/test/regress/expected/object_address.out b/src/test/regress/expected/object_address.out index 97227d67a54..5e53f0b092e 100644 --- a/src/test/regress/expected/object_address.out +++ b/src/test/regress/expected/object_address.out @@ -67,7 +67,9 @@ DECLARE BEGIN FOR objtype IN VALUES ('toast table'), ('index column'), ('sequence column'), ('toast table column'), ('view column'), ('materialized view column'), - ('property graph element'), ('property graph label'), ('property graph property') + ('property graph element'), ('property graph element label'), + ('property graph label'), ('property graph label property'), + ('property graph property') LOOP BEGIN PERFORM pg_get_object_address(objtype, '{one}', '{}'); @@ -84,7 +86,9 @@ WARNING: error for toast table column: unsupported object type "toast table col WARNING: error for view column: unsupported object type "view column" WARNING: error for materialized view column: unsupported object type "materialized view column" WARNING: error for property graph element: unsupported object type "property graph element" +WARNING: error for property graph element label: unrecognized object type "property graph element label" WARNING: error for property graph label: unsupported object type "property graph label" +WARNING: error for property graph label property: unrecognized object type "property graph label property" WARNING: error for property graph property: unsupported object type "property graph property" -- miscellaneous other errors select * from pg_get_object_address('operator of access method', '{btree,integer_ops,1}', '{int4,bool}'); @@ -593,7 +597,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace @@ -653,6 +659,8 @@ ORDER BY objects.classid, objects.objid, objects.objsubid; ("(""parameter ACL"",,,)")|("(""parameter ACL"",,)")|NULL ("(""property graph element"",,,)")|("(""property graph element"",,)")|NULL ("(""property graph label"",,,)")|("(""property graph label"",,)")|NULL +("(""property graph element label"",,,)")|("(""property graph element label"",,)")|NULL ("(""property graph property"",,,)")|("(""property graph property"",,)")|NULL +("(""property graph label property"",,,)")|("(""property graph label property"",,)")|NULL -- restore normal output mode \a\t diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..9608dd5c4af 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -298,6 +298,29 @@ SELECT (pg_identify_object(classid, objid, objsubid)).* refobjid = 'create_property_graph_tests.g2'::regclass ORDER BY 1, 2, 3, 4; +-- test object address functions with recursive dependency walk +-- covers all property graph object types including indirect dependents +SELECT * +FROM ( + WITH RECURSIVE deps (classid, objid, objsubid, refclassid, refobjid, refobjsubid) AS ( + SELECT classid, objid, objsubid, + refclassid, refobjid, refobjsubid + FROM pg_depend + WHERE refclassid = 'pg_class'::regclass AND + refobjid = 'create_property_graph_tests.gt'::regclass + UNION ALL + SELECT d.classid, d.objid, d.objsubid, + d.refclassid, d.refobjid, d.refobjsubid + FROM pg_depend d + JOIN deps dp ON d.refclassid = dp.classid AND d.refobjid = dp.objid AND d.refobjsubid = dp.objsubid + ) + SELECT pg_describe_object(classid, objid, objsubid) as obj, + pg_identify_object(classid, objid, objsubid) as ident, + pg_identify_object_as_address(classid, objid, objsubid) as addr + FROM deps +) s +ORDER BY obj COLLATE "C", ident::text COLLATE "C"; + \a\t SELECT pg_get_propgraphdef('g2'::regclass); SELECT pg_get_propgraphdef('g3'::regclass); diff --git a/src/test/regress/sql/event_trigger.sql b/src/test/regress/sql/event_trigger.sql index 32e9bb58c5e..271f443378b 100644 --- a/src/test/regress/sql/event_trigger.sql +++ b/src/test/regress/sql/event_trigger.sql @@ -143,6 +143,19 @@ create user mapping for regress_evt_user server useless_server; alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +CREATE TABLE t2x (i int PRIMARY KEY, j text); + +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); + +DROP PROPERTY GRAPH gx; +DROP TABLE t1x, t2x; + -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; diff --git a/src/test/regress/sql/object_address.sql b/src/test/regress/sql/object_address.sql index 1bbe9457c1c..27109d421c7 100644 --- a/src/test/regress/sql/object_address.sql +++ b/src/test/regress/sql/object_address.sql @@ -67,7 +67,9 @@ DECLARE BEGIN FOR objtype IN VALUES ('toast table'), ('index column'), ('sequence column'), ('toast table column'), ('view column'), ('materialized view column'), - ('property graph element'), ('property graph label'), ('property graph property') + ('property graph element'), ('property graph element label'), + ('property graph label'), ('property graph label property'), + ('property graph property') LOOP BEGIN PERFORM pg_get_object_address(objtype, '{one}', '{}'); @@ -282,7 +284,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace -- 2.34.1 --R84XrR4Hgw0dH3Ec-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v3] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-23 09:27 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-23 09:27 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing them to hit the default case and error out with "unsupported object class". During DROP PROPERTY GRAPH, this manifests when an event trigger is active, because pg_event_trigger_ddl_commands() calls these functions. The same code paths are also reachable via pg_identify_object() and pg_identify_object_as_address(). This commit adds the missing cases. Test coverage is added in object_address.sql for these two catalog types and in create_property_graph.sql covering all property graph object types. A test in event_trigger.sql verifies that DROP PROPERTY GRAPH works correctly when an event trigger is active. Author: Bertrand Drouvot <[email protected]> Reviewed-by: Michael Paquier <[email protected]> Reviewed-by: Ashutosh Bapat <[email protected]> Discussion: https://postgr.es/m/aej1DkLwhyZWmtxJ@bdtpg --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 78 ++++++++++++++++ src/test/regress/expected/event_trigger.out | 17 ++++ src/test/regress/expected/object_address.out | 10 +- .../regress/sql/create_property_graph.sql | 23 +++++ src/test/regress/sql/event_trigger.sql | 13 +++ src/test/regress/sql/object_address.sql | 6 +- 7 files changed, 238 insertions(+), 2 deletions(-) 14.7% src/backend/catalog/ 75.5% src/test/regress/expected/ 9.7% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..eb9e17fb727 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -752,6 +752,84 @@ SELECT (pg_identify_object(classid, objid, objsubid)).* type | create_property_graph_tests | g2 | create_property_graph_tests.g2 (21 rows) +-- test object address functions with recursive dependency walk +-- covers all property graph object types including indirect dependents +SELECT * +FROM ( + WITH RECURSIVE deps (classid, objid, objsubid, refclassid, refobjid, refobjsubid) AS ( + SELECT classid, objid, objsubid, + refclassid, refobjid, refobjsubid + FROM pg_depend + WHERE refclassid = 'pg_class'::regclass AND + refobjid = 'create_property_graph_tests.gt'::regclass + UNION ALL + SELECT d.classid, d.objid, d.objsubid, + d.refclassid, d.refobjid, d.refobjsubid + FROM pg_depend d + JOIN deps dp ON d.refclassid = dp.classid AND d.refobjid = dp.objid AND d.refobjsubid = dp.objsubid + ) + SELECT pg_describe_object(classid, objid, objsubid) as obj, + pg_identify_object(classid, objid, objsubid) as ident, + pg_identify_object_as_address(classid, objid, objsubid) as addr + FROM deps +) s +ORDER BY obj COLLATE "C", ident::text COLLATE "C"; + obj | ident | addr +----------------------------------------------------------+----------------------------------------------------------------------------+---------------------------------------------------------------------------- + edge e of property graph gt | ("property graph element",,,"e of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,e}",{}) + edge e of property graph gt | ("property graph element",,,"e of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,e}",{}) + edge e of property graph gt | ("property graph element",,,"e of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of property graph gt | ("property graph label",,,"e of create_property_graph_tests.gt") | ("property graph label","{create_property_graph_tests,gt,e}",{}) + label v1 of property graph gt | ("property graph label",,,"v1 of create_property_graph_tests.gt") | ("property graph label","{create_property_graph_tests,gt,v1}",{}) + label v1 of vertex v1 of property graph gt | ("property graph element label",,,"v1 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v1}",{}) + label v1 of vertex v1 of property graph gt | ("property graph element label",,,"v1 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v1}",{}) + label v2 of property graph gt | ("property graph label",,,"v2 of create_property_graph_tests.gt") | ("property graph label","{create_property_graph_tests,gt,v2}",{}) + label v2 of vertex v2 of property graph gt | ("property graph element label",,,"v2 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v2}",{}) + label v2 of vertex v2 of property graph gt | ("property graph element label",,,"v2 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v2}",{}) + property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property a of property graph gt | ("property graph property",,,"a of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,a}",{}) + property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property b of property graph gt | ("property graph property",,,"b of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,b}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of property graph gt | ("property graph property",,,"c of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,c}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of property graph gt | ("property graph property",,,"k1 of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,k1}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of property graph gt | ("property graph property",,,"k2 of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,k2}",{}) + property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property m of property graph gt | ("property graph property",,,"m of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,m}",{}) + property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property n of property graph gt | ("property graph property",,,"n of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,n}",{}) + type gt | (type,create_property_graph_tests,gt,create_property_graph_tests.gt) | (type,{create_property_graph_tests.gt},{}) + type gt[] | (type,create_property_graph_tests,_gt,create_property_graph_tests.gt[]) | (type,{create_property_graph_tests.gt[]},{}) + vertex v1 of property graph gt | ("property graph element",,,"v1 of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,v1}",{}) + vertex v2 of property graph gt | ("property graph element",,,"v2 of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,v2}",{}) +(52 rows) + \a\t SELECT pg_get_propgraphdef('g2'::regclass); CREATE PROPERTY GRAPH create_property_graph_tests.g2 diff --git a/src/test/regress/expected/event_trigger.out b/src/test/regress/expected/event_trigger.out index 065f586310f..ed8d5df397e 100644 --- a/src/test/regress/expected/event_trigger.out +++ b/src/test/regress/expected/event_trigger.out @@ -173,6 +173,23 @@ NOTICE: test_event_trigger: ddl_command_end CREATE USER MAPPING alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; NOTICE: test_event_trigger: ddl_command_end ALTER DEFAULT PRIVILEGES +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE TABLE t2x (i int PRIMARY KEY, j text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); +NOTICE: test_event_trigger: ddl_command_end CREATE PROPERTY GRAPH +DROP PROPERTY GRAPH gx; +NOTICE: test_event_trigger: ddl_command_end DROP PROPERTY GRAPH +DROP TABLE t1x, t2x; +NOTICE: test_event_trigger: ddl_command_end DROP TABLE -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; ERROR: permission denied to change owner of event trigger "regress_event_trigger" diff --git a/src/test/regress/expected/object_address.out b/src/test/regress/expected/object_address.out index 97227d67a54..5e53f0b092e 100644 --- a/src/test/regress/expected/object_address.out +++ b/src/test/regress/expected/object_address.out @@ -67,7 +67,9 @@ DECLARE BEGIN FOR objtype IN VALUES ('toast table'), ('index column'), ('sequence column'), ('toast table column'), ('view column'), ('materialized view column'), - ('property graph element'), ('property graph label'), ('property graph property') + ('property graph element'), ('property graph element label'), + ('property graph label'), ('property graph label property'), + ('property graph property') LOOP BEGIN PERFORM pg_get_object_address(objtype, '{one}', '{}'); @@ -84,7 +86,9 @@ WARNING: error for toast table column: unsupported object type "toast table col WARNING: error for view column: unsupported object type "view column" WARNING: error for materialized view column: unsupported object type "materialized view column" WARNING: error for property graph element: unsupported object type "property graph element" +WARNING: error for property graph element label: unrecognized object type "property graph element label" WARNING: error for property graph label: unsupported object type "property graph label" +WARNING: error for property graph label property: unrecognized object type "property graph label property" WARNING: error for property graph property: unsupported object type "property graph property" -- miscellaneous other errors select * from pg_get_object_address('operator of access method', '{btree,integer_ops,1}', '{int4,bool}'); @@ -593,7 +597,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace @@ -653,6 +659,8 @@ ORDER BY objects.classid, objects.objid, objects.objsubid; ("(""parameter ACL"",,,)")|("(""parameter ACL"",,)")|NULL ("(""property graph element"",,,)")|("(""property graph element"",,)")|NULL ("(""property graph label"",,,)")|("(""property graph label"",,)")|NULL +("(""property graph element label"",,,)")|("(""property graph element label"",,)")|NULL ("(""property graph property"",,,)")|("(""property graph property"",,)")|NULL +("(""property graph label property"",,,)")|("(""property graph label property"",,)")|NULL -- restore normal output mode \a\t diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..9608dd5c4af 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -298,6 +298,29 @@ SELECT (pg_identify_object(classid, objid, objsubid)).* refobjid = 'create_property_graph_tests.g2'::regclass ORDER BY 1, 2, 3, 4; +-- test object address functions with recursive dependency walk +-- covers all property graph object types including indirect dependents +SELECT * +FROM ( + WITH RECURSIVE deps (classid, objid, objsubid, refclassid, refobjid, refobjsubid) AS ( + SELECT classid, objid, objsubid, + refclassid, refobjid, refobjsubid + FROM pg_depend + WHERE refclassid = 'pg_class'::regclass AND + refobjid = 'create_property_graph_tests.gt'::regclass + UNION ALL + SELECT d.classid, d.objid, d.objsubid, + d.refclassid, d.refobjid, d.refobjsubid + FROM pg_depend d + JOIN deps dp ON d.refclassid = dp.classid AND d.refobjid = dp.objid AND d.refobjsubid = dp.objsubid + ) + SELECT pg_describe_object(classid, objid, objsubid) as obj, + pg_identify_object(classid, objid, objsubid) as ident, + pg_identify_object_as_address(classid, objid, objsubid) as addr + FROM deps +) s +ORDER BY obj COLLATE "C", ident::text COLLATE "C"; + \a\t SELECT pg_get_propgraphdef('g2'::regclass); SELECT pg_get_propgraphdef('g3'::regclass); diff --git a/src/test/regress/sql/event_trigger.sql b/src/test/regress/sql/event_trigger.sql index 32e9bb58c5e..271f443378b 100644 --- a/src/test/regress/sql/event_trigger.sql +++ b/src/test/regress/sql/event_trigger.sql @@ -143,6 +143,19 @@ create user mapping for regress_evt_user server useless_server; alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +CREATE TABLE t2x (i int PRIMARY KEY, j text); + +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); + +DROP PROPERTY GRAPH gx; +DROP TABLE t1x, t2x; + -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; diff --git a/src/test/regress/sql/object_address.sql b/src/test/regress/sql/object_address.sql index 1bbe9457c1c..27109d421c7 100644 --- a/src/test/regress/sql/object_address.sql +++ b/src/test/regress/sql/object_address.sql @@ -67,7 +67,9 @@ DECLARE BEGIN FOR objtype IN VALUES ('toast table'), ('index column'), ('sequence column'), ('toast table column'), ('view column'), ('materialized view column'), - ('property graph element'), ('property graph label'), ('property graph property') + ('property graph element'), ('property graph element label'), + ('property graph label'), ('property graph label property'), + ('property graph property') LOOP BEGIN PERFORM pg_get_object_address(objtype, '{one}', '{}'); @@ -282,7 +284,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace -- 2.34.1 --R84XrR4Hgw0dH3Ec-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v3] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-23 09:27 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-23 09:27 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing them to hit the default case and error out with "unsupported object class". During DROP PROPERTY GRAPH, this manifests when an event trigger is active, because pg_event_trigger_ddl_commands() calls these functions. The same code paths are also reachable via pg_identify_object() and pg_identify_object_as_address(). This commit adds the missing cases. Test coverage is added in object_address.sql for these two catalog types and in create_property_graph.sql covering all property graph object types. A test in event_trigger.sql verifies that DROP PROPERTY GRAPH works correctly when an event trigger is active. Author: Bertrand Drouvot <[email protected]> Reviewed-by: Michael Paquier <[email protected]> Reviewed-by: Ashutosh Bapat <[email protected]> Discussion: https://postgr.es/m/aej1DkLwhyZWmtxJ@bdtpg --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 78 ++++++++++++++++ src/test/regress/expected/event_trigger.out | 17 ++++ src/test/regress/expected/object_address.out | 10 +- .../regress/sql/create_property_graph.sql | 23 +++++ src/test/regress/sql/event_trigger.sql | 13 +++ src/test/regress/sql/object_address.sql | 6 +- 7 files changed, 238 insertions(+), 2 deletions(-) 14.7% src/backend/catalog/ 75.5% src/test/regress/expected/ 9.7% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..eb9e17fb727 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -752,6 +752,84 @@ SELECT (pg_identify_object(classid, objid, objsubid)).* type | create_property_graph_tests | g2 | create_property_graph_tests.g2 (21 rows) +-- test object address functions with recursive dependency walk +-- covers all property graph object types including indirect dependents +SELECT * +FROM ( + WITH RECURSIVE deps (classid, objid, objsubid, refclassid, refobjid, refobjsubid) AS ( + SELECT classid, objid, objsubid, + refclassid, refobjid, refobjsubid + FROM pg_depend + WHERE refclassid = 'pg_class'::regclass AND + refobjid = 'create_property_graph_tests.gt'::regclass + UNION ALL + SELECT d.classid, d.objid, d.objsubid, + d.refclassid, d.refobjid, d.refobjsubid + FROM pg_depend d + JOIN deps dp ON d.refclassid = dp.classid AND d.refobjid = dp.objid AND d.refobjsubid = dp.objsubid + ) + SELECT pg_describe_object(classid, objid, objsubid) as obj, + pg_identify_object(classid, objid, objsubid) as ident, + pg_identify_object_as_address(classid, objid, objsubid) as addr + FROM deps +) s +ORDER BY obj COLLATE "C", ident::text COLLATE "C"; + obj | ident | addr +----------------------------------------------------------+----------------------------------------------------------------------------+---------------------------------------------------------------------------- + edge e of property graph gt | ("property graph element",,,"e of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,e}",{}) + edge e of property graph gt | ("property graph element",,,"e of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,e}",{}) + edge e of property graph gt | ("property graph element",,,"e of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of property graph gt | ("property graph label",,,"e of create_property_graph_tests.gt") | ("property graph label","{create_property_graph_tests,gt,e}",{}) + label v1 of property graph gt | ("property graph label",,,"v1 of create_property_graph_tests.gt") | ("property graph label","{create_property_graph_tests,gt,v1}",{}) + label v1 of vertex v1 of property graph gt | ("property graph element label",,,"v1 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v1}",{}) + label v1 of vertex v1 of property graph gt | ("property graph element label",,,"v1 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v1}",{}) + label v2 of property graph gt | ("property graph label",,,"v2 of create_property_graph_tests.gt") | ("property graph label","{create_property_graph_tests,gt,v2}",{}) + label v2 of vertex v2 of property graph gt | ("property graph element label",,,"v2 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v2}",{}) + label v2 of vertex v2 of property graph gt | ("property graph element label",,,"v2 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v2}",{}) + property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property a of property graph gt | ("property graph property",,,"a of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,a}",{}) + property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property b of property graph gt | ("property graph property",,,"b of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,b}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of property graph gt | ("property graph property",,,"c of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,c}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of property graph gt | ("property graph property",,,"k1 of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,k1}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of property graph gt | ("property graph property",,,"k2 of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,k2}",{}) + property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property m of property graph gt | ("property graph property",,,"m of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,m}",{}) + property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property n of property graph gt | ("property graph property",,,"n of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,n}",{}) + type gt | (type,create_property_graph_tests,gt,create_property_graph_tests.gt) | (type,{create_property_graph_tests.gt},{}) + type gt[] | (type,create_property_graph_tests,_gt,create_property_graph_tests.gt[]) | (type,{create_property_graph_tests.gt[]},{}) + vertex v1 of property graph gt | ("property graph element",,,"v1 of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,v1}",{}) + vertex v2 of property graph gt | ("property graph element",,,"v2 of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,v2}",{}) +(52 rows) + \a\t SELECT pg_get_propgraphdef('g2'::regclass); CREATE PROPERTY GRAPH create_property_graph_tests.g2 diff --git a/src/test/regress/expected/event_trigger.out b/src/test/regress/expected/event_trigger.out index 065f586310f..ed8d5df397e 100644 --- a/src/test/regress/expected/event_trigger.out +++ b/src/test/regress/expected/event_trigger.out @@ -173,6 +173,23 @@ NOTICE: test_event_trigger: ddl_command_end CREATE USER MAPPING alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; NOTICE: test_event_trigger: ddl_command_end ALTER DEFAULT PRIVILEGES +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE TABLE t2x (i int PRIMARY KEY, j text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); +NOTICE: test_event_trigger: ddl_command_end CREATE PROPERTY GRAPH +DROP PROPERTY GRAPH gx; +NOTICE: test_event_trigger: ddl_command_end DROP PROPERTY GRAPH +DROP TABLE t1x, t2x; +NOTICE: test_event_trigger: ddl_command_end DROP TABLE -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; ERROR: permission denied to change owner of event trigger "regress_event_trigger" diff --git a/src/test/regress/expected/object_address.out b/src/test/regress/expected/object_address.out index 97227d67a54..5e53f0b092e 100644 --- a/src/test/regress/expected/object_address.out +++ b/src/test/regress/expected/object_address.out @@ -67,7 +67,9 @@ DECLARE BEGIN FOR objtype IN VALUES ('toast table'), ('index column'), ('sequence column'), ('toast table column'), ('view column'), ('materialized view column'), - ('property graph element'), ('property graph label'), ('property graph property') + ('property graph element'), ('property graph element label'), + ('property graph label'), ('property graph label property'), + ('property graph property') LOOP BEGIN PERFORM pg_get_object_address(objtype, '{one}', '{}'); @@ -84,7 +86,9 @@ WARNING: error for toast table column: unsupported object type "toast table col WARNING: error for view column: unsupported object type "view column" WARNING: error for materialized view column: unsupported object type "materialized view column" WARNING: error for property graph element: unsupported object type "property graph element" +WARNING: error for property graph element label: unrecognized object type "property graph element label" WARNING: error for property graph label: unsupported object type "property graph label" +WARNING: error for property graph label property: unrecognized object type "property graph label property" WARNING: error for property graph property: unsupported object type "property graph property" -- miscellaneous other errors select * from pg_get_object_address('operator of access method', '{btree,integer_ops,1}', '{int4,bool}'); @@ -593,7 +597,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace @@ -653,6 +659,8 @@ ORDER BY objects.classid, objects.objid, objects.objsubid; ("(""parameter ACL"",,,)")|("(""parameter ACL"",,)")|NULL ("(""property graph element"",,,)")|("(""property graph element"",,)")|NULL ("(""property graph label"",,,)")|("(""property graph label"",,)")|NULL +("(""property graph element label"",,,)")|("(""property graph element label"",,)")|NULL ("(""property graph property"",,,)")|("(""property graph property"",,)")|NULL +("(""property graph label property"",,,)")|("(""property graph label property"",,)")|NULL -- restore normal output mode \a\t diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..9608dd5c4af 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -298,6 +298,29 @@ SELECT (pg_identify_object(classid, objid, objsubid)).* refobjid = 'create_property_graph_tests.g2'::regclass ORDER BY 1, 2, 3, 4; +-- test object address functions with recursive dependency walk +-- covers all property graph object types including indirect dependents +SELECT * +FROM ( + WITH RECURSIVE deps (classid, objid, objsubid, refclassid, refobjid, refobjsubid) AS ( + SELECT classid, objid, objsubid, + refclassid, refobjid, refobjsubid + FROM pg_depend + WHERE refclassid = 'pg_class'::regclass AND + refobjid = 'create_property_graph_tests.gt'::regclass + UNION ALL + SELECT d.classid, d.objid, d.objsubid, + d.refclassid, d.refobjid, d.refobjsubid + FROM pg_depend d + JOIN deps dp ON d.refclassid = dp.classid AND d.refobjid = dp.objid AND d.refobjsubid = dp.objsubid + ) + SELECT pg_describe_object(classid, objid, objsubid) as obj, + pg_identify_object(classid, objid, objsubid) as ident, + pg_identify_object_as_address(classid, objid, objsubid) as addr + FROM deps +) s +ORDER BY obj COLLATE "C", ident::text COLLATE "C"; + \a\t SELECT pg_get_propgraphdef('g2'::regclass); SELECT pg_get_propgraphdef('g3'::regclass); diff --git a/src/test/regress/sql/event_trigger.sql b/src/test/regress/sql/event_trigger.sql index 32e9bb58c5e..271f443378b 100644 --- a/src/test/regress/sql/event_trigger.sql +++ b/src/test/regress/sql/event_trigger.sql @@ -143,6 +143,19 @@ create user mapping for regress_evt_user server useless_server; alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +CREATE TABLE t2x (i int PRIMARY KEY, j text); + +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); + +DROP PROPERTY GRAPH gx; +DROP TABLE t1x, t2x; + -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; diff --git a/src/test/regress/sql/object_address.sql b/src/test/regress/sql/object_address.sql index 1bbe9457c1c..27109d421c7 100644 --- a/src/test/regress/sql/object_address.sql +++ b/src/test/regress/sql/object_address.sql @@ -67,7 +67,9 @@ DECLARE BEGIN FOR objtype IN VALUES ('toast table'), ('index column'), ('sequence column'), ('toast table column'), ('view column'), ('materialized view column'), - ('property graph element'), ('property graph label'), ('property graph property') + ('property graph element'), ('property graph element label'), + ('property graph label'), ('property graph label property'), + ('property graph property') LOOP BEGIN PERFORM pg_get_object_address(objtype, '{one}', '{}'); @@ -282,7 +284,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace -- 2.34.1 --R84XrR4Hgw0dH3Ec-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v2] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-23 09:27 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-23 09:27 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing them to hit the default case and error out with "unsupported object class". During DROP PROPERTY GRAPH, this manifests when an event trigger is active, because pg_event_trigger_ddl_commands() calls these functions. The same code paths are also reachable via pg_identify_object() and pg_identify_object_as_address(). This commit adds the missing cases. Test coverage is added in object_address.sql for these two catalog types via the zero-OID test that exercises pg_identify_object() and pg_identify_object_as_address(). A test in event_trigger.sql verifies that DROP PROPERTY GRAPH works correctly when an event trigger is active. Author: Bertrand Drouvot <[email protected]> Reviewed-by: Michael Paquier <[email protected]> Reviewed-by: Ashutosh Bapat <[email protected]> Discussion: https://postgr.es/m/aej1DkLwhyZWmtxJ@bdtpg --- src/backend/catalog/objectaddress.c | 93 ++++++++++++++++++++ src/test/regress/expected/event_trigger.out | 17 ++++ src/test/regress/expected/object_address.out | 4 + src/test/regress/sql/event_trigger.sql | 13 +++ src/test/regress/sql/object_address.sql | 2 + 5 files changed, 129 insertions(+) 62.4% src/backend/catalog/ 25.6% src/test/regress/expected/ 11.8% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/event_trigger.out b/src/test/regress/expected/event_trigger.out index 065f586310f..ed8d5df397e 100644 --- a/src/test/regress/expected/event_trigger.out +++ b/src/test/regress/expected/event_trigger.out @@ -173,6 +173,23 @@ NOTICE: test_event_trigger: ddl_command_end CREATE USER MAPPING alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; NOTICE: test_event_trigger: ddl_command_end ALTER DEFAULT PRIVILEGES +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE TABLE t2x (i int PRIMARY KEY, j text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); +NOTICE: test_event_trigger: ddl_command_end CREATE PROPERTY GRAPH +DROP PROPERTY GRAPH gx; +NOTICE: test_event_trigger: ddl_command_end DROP PROPERTY GRAPH +DROP TABLE t1x, t2x; +NOTICE: test_event_trigger: ddl_command_end DROP TABLE -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; ERROR: permission denied to change owner of event trigger "regress_event_trigger" diff --git a/src/test/regress/expected/object_address.out b/src/test/regress/expected/object_address.out index 97227d67a54..729c3537f25 100644 --- a/src/test/regress/expected/object_address.out +++ b/src/test/regress/expected/object_address.out @@ -593,7 +593,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace @@ -653,6 +655,8 @@ ORDER BY objects.classid, objects.objid, objects.objsubid; ("(""parameter ACL"",,,)")|("(""parameter ACL"",,)")|NULL ("(""property graph element"",,,)")|("(""property graph element"",,)")|NULL ("(""property graph label"",,,)")|("(""property graph label"",,)")|NULL +("(""property graph element label"",,,)")|("(""property graph element label"",,)")|NULL ("(""property graph property"",,,)")|("(""property graph property"",,)")|NULL +("(""property graph label property"",,,)")|("(""property graph label property"",,)")|NULL -- restore normal output mode \a\t diff --git a/src/test/regress/sql/event_trigger.sql b/src/test/regress/sql/event_trigger.sql index 32e9bb58c5e..271f443378b 100644 --- a/src/test/regress/sql/event_trigger.sql +++ b/src/test/regress/sql/event_trigger.sql @@ -143,6 +143,19 @@ create user mapping for regress_evt_user server useless_server; alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +CREATE TABLE t2x (i int PRIMARY KEY, j text); + +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); + +DROP PROPERTY GRAPH gx; +DROP TABLE t1x, t2x; + -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; diff --git a/src/test/regress/sql/object_address.sql b/src/test/regress/sql/object_address.sql index 1bbe9457c1c..620dacf1045 100644 --- a/src/test/regress/sql/object_address.sql +++ b/src/test/regress/sql/object_address.sql @@ -282,7 +282,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace -- 2.34.1 --gtUR827Uq8d5gVsQ-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v2] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-23 09:27 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-23 09:27 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing them to hit the default case and error out with "unsupported object class". During DROP PROPERTY GRAPH, this manifests when an event trigger is active, because pg_event_trigger_ddl_commands() calls these functions. The same code paths are also reachable via pg_identify_object() and pg_identify_object_as_address(). This commit adds the missing cases. Test coverage is added in object_address.sql for these two catalog types via the zero-OID test that exercises pg_identify_object() and pg_identify_object_as_address(). A test in event_trigger.sql verifies that DROP PROPERTY GRAPH works correctly when an event trigger is active. Author: Bertrand Drouvot <[email protected]> Reviewed-by: Michael Paquier <[email protected]> Reviewed-by: Ashutosh Bapat <[email protected]> Discussion: https://postgr.es/m/aej1DkLwhyZWmtxJ@bdtpg --- src/backend/catalog/objectaddress.c | 93 ++++++++++++++++++++ src/test/regress/expected/event_trigger.out | 17 ++++ src/test/regress/expected/object_address.out | 4 + src/test/regress/sql/event_trigger.sql | 13 +++ src/test/regress/sql/object_address.sql | 2 + 5 files changed, 129 insertions(+) 62.4% src/backend/catalog/ 25.6% src/test/regress/expected/ 11.8% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/event_trigger.out b/src/test/regress/expected/event_trigger.out index 065f586310f..ed8d5df397e 100644 --- a/src/test/regress/expected/event_trigger.out +++ b/src/test/regress/expected/event_trigger.out @@ -173,6 +173,23 @@ NOTICE: test_event_trigger: ddl_command_end CREATE USER MAPPING alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; NOTICE: test_event_trigger: ddl_command_end ALTER DEFAULT PRIVILEGES +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE TABLE t2x (i int PRIMARY KEY, j text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); +NOTICE: test_event_trigger: ddl_command_end CREATE PROPERTY GRAPH +DROP PROPERTY GRAPH gx; +NOTICE: test_event_trigger: ddl_command_end DROP PROPERTY GRAPH +DROP TABLE t1x, t2x; +NOTICE: test_event_trigger: ddl_command_end DROP TABLE -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; ERROR: permission denied to change owner of event trigger "regress_event_trigger" diff --git a/src/test/regress/expected/object_address.out b/src/test/regress/expected/object_address.out index 97227d67a54..729c3537f25 100644 --- a/src/test/regress/expected/object_address.out +++ b/src/test/regress/expected/object_address.out @@ -593,7 +593,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace @@ -653,6 +655,8 @@ ORDER BY objects.classid, objects.objid, objects.objsubid; ("(""parameter ACL"",,,)")|("(""parameter ACL"",,)")|NULL ("(""property graph element"",,,)")|("(""property graph element"",,)")|NULL ("(""property graph label"",,,)")|("(""property graph label"",,)")|NULL +("(""property graph element label"",,,)")|("(""property graph element label"",,)")|NULL ("(""property graph property"",,,)")|("(""property graph property"",,)")|NULL +("(""property graph label property"",,,)")|("(""property graph label property"",,)")|NULL -- restore normal output mode \a\t diff --git a/src/test/regress/sql/event_trigger.sql b/src/test/regress/sql/event_trigger.sql index 32e9bb58c5e..271f443378b 100644 --- a/src/test/regress/sql/event_trigger.sql +++ b/src/test/regress/sql/event_trigger.sql @@ -143,6 +143,19 @@ create user mapping for regress_evt_user server useless_server; alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +CREATE TABLE t2x (i int PRIMARY KEY, j text); + +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); + +DROP PROPERTY GRAPH gx; +DROP TABLE t1x, t2x; + -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; diff --git a/src/test/regress/sql/object_address.sql b/src/test/regress/sql/object_address.sql index 1bbe9457c1c..620dacf1045 100644 --- a/src/test/regress/sql/object_address.sql +++ b/src/test/regress/sql/object_address.sql @@ -282,7 +282,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace -- 2.34.1 --gtUR827Uq8d5gVsQ-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v2] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-23 09:27 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-23 09:27 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing them to hit the default case and error out with "unsupported object class". During DROP PROPERTY GRAPH, this manifests when an event trigger is active, because pg_event_trigger_ddl_commands() calls these functions. The same code paths are also reachable via pg_identify_object() and pg_identify_object_as_address(). This commit adds the missing cases. Test coverage is added in object_address.sql for these two catalog types via the zero-OID test that exercises pg_identify_object() and pg_identify_object_as_address(). A test in event_trigger.sql verifies that DROP PROPERTY GRAPH works correctly when an event trigger is active. Author: Bertrand Drouvot <[email protected]> Reviewed-by: Michael Paquier <[email protected]> Reviewed-by: Ashutosh Bapat <[email protected]> Discussion: https://postgr.es/m/aej1DkLwhyZWmtxJ@bdtpg --- src/backend/catalog/objectaddress.c | 93 ++++++++++++++++++++ src/test/regress/expected/event_trigger.out | 17 ++++ src/test/regress/expected/object_address.out | 4 + src/test/regress/sql/event_trigger.sql | 13 +++ src/test/regress/sql/object_address.sql | 2 + 5 files changed, 129 insertions(+) 62.4% src/backend/catalog/ 25.6% src/test/regress/expected/ 11.8% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/event_trigger.out b/src/test/regress/expected/event_trigger.out index 065f586310f..ed8d5df397e 100644 --- a/src/test/regress/expected/event_trigger.out +++ b/src/test/regress/expected/event_trigger.out @@ -173,6 +173,23 @@ NOTICE: test_event_trigger: ddl_command_end CREATE USER MAPPING alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; NOTICE: test_event_trigger: ddl_command_end ALTER DEFAULT PRIVILEGES +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE TABLE t2x (i int PRIMARY KEY, j text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); +NOTICE: test_event_trigger: ddl_command_end CREATE PROPERTY GRAPH +DROP PROPERTY GRAPH gx; +NOTICE: test_event_trigger: ddl_command_end DROP PROPERTY GRAPH +DROP TABLE t1x, t2x; +NOTICE: test_event_trigger: ddl_command_end DROP TABLE -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; ERROR: permission denied to change owner of event trigger "regress_event_trigger" diff --git a/src/test/regress/expected/object_address.out b/src/test/regress/expected/object_address.out index 97227d67a54..729c3537f25 100644 --- a/src/test/regress/expected/object_address.out +++ b/src/test/regress/expected/object_address.out @@ -593,7 +593,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace @@ -653,6 +655,8 @@ ORDER BY objects.classid, objects.objid, objects.objsubid; ("(""parameter ACL"",,,)")|("(""parameter ACL"",,)")|NULL ("(""property graph element"",,,)")|("(""property graph element"",,)")|NULL ("(""property graph label"",,,)")|("(""property graph label"",,)")|NULL +("(""property graph element label"",,,)")|("(""property graph element label"",,)")|NULL ("(""property graph property"",,,)")|("(""property graph property"",,)")|NULL +("(""property graph label property"",,,)")|("(""property graph label property"",,)")|NULL -- restore normal output mode \a\t diff --git a/src/test/regress/sql/event_trigger.sql b/src/test/regress/sql/event_trigger.sql index 32e9bb58c5e..271f443378b 100644 --- a/src/test/regress/sql/event_trigger.sql +++ b/src/test/regress/sql/event_trigger.sql @@ -143,6 +143,19 @@ create user mapping for regress_evt_user server useless_server; alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +CREATE TABLE t2x (i int PRIMARY KEY, j text); + +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); + +DROP PROPERTY GRAPH gx; +DROP TABLE t1x, t2x; + -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; diff --git a/src/test/regress/sql/object_address.sql b/src/test/regress/sql/object_address.sql index 1bbe9457c1c..620dacf1045 100644 --- a/src/test/regress/sql/object_address.sql +++ b/src/test/regress/sql/object_address.sql @@ -282,7 +282,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace -- 2.34.1 --gtUR827Uq8d5gVsQ-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v3] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-23 09:27 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-23 09:27 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing them to hit the default case and error out with "unsupported object class". During DROP PROPERTY GRAPH, this manifests when an event trigger is active, because pg_event_trigger_ddl_commands() calls these functions. The same code paths are also reachable via pg_identify_object() and pg_identify_object_as_address(). This commit adds the missing cases. Test coverage is added in object_address.sql for these two catalog types and in create_property_graph.sql covering all property graph object types. A test in event_trigger.sql verifies that DROP PROPERTY GRAPH works correctly when an event trigger is active. Author: Bertrand Drouvot <[email protected]> Reviewed-by: Michael Paquier <[email protected]> Reviewed-by: Ashutosh Bapat <[email protected]> Discussion: https://postgr.es/m/aej1DkLwhyZWmtxJ@bdtpg --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 78 ++++++++++++++++ src/test/regress/expected/event_trigger.out | 17 ++++ src/test/regress/expected/object_address.out | 10 +- .../regress/sql/create_property_graph.sql | 23 +++++ src/test/regress/sql/event_trigger.sql | 13 +++ src/test/regress/sql/object_address.sql | 6 +- 7 files changed, 238 insertions(+), 2 deletions(-) 14.7% src/backend/catalog/ 75.5% src/test/regress/expected/ 9.7% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..eb9e17fb727 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -752,6 +752,84 @@ SELECT (pg_identify_object(classid, objid, objsubid)).* type | create_property_graph_tests | g2 | create_property_graph_tests.g2 (21 rows) +-- test object address functions with recursive dependency walk +-- covers all property graph object types including indirect dependents +SELECT * +FROM ( + WITH RECURSIVE deps (classid, objid, objsubid, refclassid, refobjid, refobjsubid) AS ( + SELECT classid, objid, objsubid, + refclassid, refobjid, refobjsubid + FROM pg_depend + WHERE refclassid = 'pg_class'::regclass AND + refobjid = 'create_property_graph_tests.gt'::regclass + UNION ALL + SELECT d.classid, d.objid, d.objsubid, + d.refclassid, d.refobjid, d.refobjsubid + FROM pg_depend d + JOIN deps dp ON d.refclassid = dp.classid AND d.refobjid = dp.objid AND d.refobjsubid = dp.objsubid + ) + SELECT pg_describe_object(classid, objid, objsubid) as obj, + pg_identify_object(classid, objid, objsubid) as ident, + pg_identify_object_as_address(classid, objid, objsubid) as addr + FROM deps +) s +ORDER BY obj COLLATE "C", ident::text COLLATE "C"; + obj | ident | addr +----------------------------------------------------------+----------------------------------------------------------------------------+---------------------------------------------------------------------------- + edge e of property graph gt | ("property graph element",,,"e of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,e}",{}) + edge e of property graph gt | ("property graph element",,,"e of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,e}",{}) + edge e of property graph gt | ("property graph element",,,"e of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of property graph gt | ("property graph label",,,"e of create_property_graph_tests.gt") | ("property graph label","{create_property_graph_tests,gt,e}",{}) + label v1 of property graph gt | ("property graph label",,,"v1 of create_property_graph_tests.gt") | ("property graph label","{create_property_graph_tests,gt,v1}",{}) + label v1 of vertex v1 of property graph gt | ("property graph element label",,,"v1 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v1}",{}) + label v1 of vertex v1 of property graph gt | ("property graph element label",,,"v1 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v1}",{}) + label v2 of property graph gt | ("property graph label",,,"v2 of create_property_graph_tests.gt") | ("property graph label","{create_property_graph_tests,gt,v2}",{}) + label v2 of vertex v2 of property graph gt | ("property graph element label",,,"v2 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v2}",{}) + label v2 of vertex v2 of property graph gt | ("property graph element label",,,"v2 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v2}",{}) + property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property a of property graph gt | ("property graph property",,,"a of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,a}",{}) + property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property b of property graph gt | ("property graph property",,,"b of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,b}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of property graph gt | ("property graph property",,,"c of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,c}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of property graph gt | ("property graph property",,,"k1 of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,k1}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of property graph gt | ("property graph property",,,"k2 of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,k2}",{}) + property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property m of property graph gt | ("property graph property",,,"m of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,m}",{}) + property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property n of property graph gt | ("property graph property",,,"n of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,n}",{}) + type gt | (type,create_property_graph_tests,gt,create_property_graph_tests.gt) | (type,{create_property_graph_tests.gt},{}) + type gt[] | (type,create_property_graph_tests,_gt,create_property_graph_tests.gt[]) | (type,{create_property_graph_tests.gt[]},{}) + vertex v1 of property graph gt | ("property graph element",,,"v1 of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,v1}",{}) + vertex v2 of property graph gt | ("property graph element",,,"v2 of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,v2}",{}) +(52 rows) + \a\t SELECT pg_get_propgraphdef('g2'::regclass); CREATE PROPERTY GRAPH create_property_graph_tests.g2 diff --git a/src/test/regress/expected/event_trigger.out b/src/test/regress/expected/event_trigger.out index 065f586310f..ed8d5df397e 100644 --- a/src/test/regress/expected/event_trigger.out +++ b/src/test/regress/expected/event_trigger.out @@ -173,6 +173,23 @@ NOTICE: test_event_trigger: ddl_command_end CREATE USER MAPPING alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; NOTICE: test_event_trigger: ddl_command_end ALTER DEFAULT PRIVILEGES +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE TABLE t2x (i int PRIMARY KEY, j text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); +NOTICE: test_event_trigger: ddl_command_end CREATE PROPERTY GRAPH +DROP PROPERTY GRAPH gx; +NOTICE: test_event_trigger: ddl_command_end DROP PROPERTY GRAPH +DROP TABLE t1x, t2x; +NOTICE: test_event_trigger: ddl_command_end DROP TABLE -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; ERROR: permission denied to change owner of event trigger "regress_event_trigger" diff --git a/src/test/regress/expected/object_address.out b/src/test/regress/expected/object_address.out index 97227d67a54..5e53f0b092e 100644 --- a/src/test/regress/expected/object_address.out +++ b/src/test/regress/expected/object_address.out @@ -67,7 +67,9 @@ DECLARE BEGIN FOR objtype IN VALUES ('toast table'), ('index column'), ('sequence column'), ('toast table column'), ('view column'), ('materialized view column'), - ('property graph element'), ('property graph label'), ('property graph property') + ('property graph element'), ('property graph element label'), + ('property graph label'), ('property graph label property'), + ('property graph property') LOOP BEGIN PERFORM pg_get_object_address(objtype, '{one}', '{}'); @@ -84,7 +86,9 @@ WARNING: error for toast table column: unsupported object type "toast table col WARNING: error for view column: unsupported object type "view column" WARNING: error for materialized view column: unsupported object type "materialized view column" WARNING: error for property graph element: unsupported object type "property graph element" +WARNING: error for property graph element label: unrecognized object type "property graph element label" WARNING: error for property graph label: unsupported object type "property graph label" +WARNING: error for property graph label property: unrecognized object type "property graph label property" WARNING: error for property graph property: unsupported object type "property graph property" -- miscellaneous other errors select * from pg_get_object_address('operator of access method', '{btree,integer_ops,1}', '{int4,bool}'); @@ -593,7 +597,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace @@ -653,6 +659,8 @@ ORDER BY objects.classid, objects.objid, objects.objsubid; ("(""parameter ACL"",,,)")|("(""parameter ACL"",,)")|NULL ("(""property graph element"",,,)")|("(""property graph element"",,)")|NULL ("(""property graph label"",,,)")|("(""property graph label"",,)")|NULL +("(""property graph element label"",,,)")|("(""property graph element label"",,)")|NULL ("(""property graph property"",,,)")|("(""property graph property"",,)")|NULL +("(""property graph label property"",,,)")|("(""property graph label property"",,)")|NULL -- restore normal output mode \a\t diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..9608dd5c4af 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -298,6 +298,29 @@ SELECT (pg_identify_object(classid, objid, objsubid)).* refobjid = 'create_property_graph_tests.g2'::regclass ORDER BY 1, 2, 3, 4; +-- test object address functions with recursive dependency walk +-- covers all property graph object types including indirect dependents +SELECT * +FROM ( + WITH RECURSIVE deps (classid, objid, objsubid, refclassid, refobjid, refobjsubid) AS ( + SELECT classid, objid, objsubid, + refclassid, refobjid, refobjsubid + FROM pg_depend + WHERE refclassid = 'pg_class'::regclass AND + refobjid = 'create_property_graph_tests.gt'::regclass + UNION ALL + SELECT d.classid, d.objid, d.objsubid, + d.refclassid, d.refobjid, d.refobjsubid + FROM pg_depend d + JOIN deps dp ON d.refclassid = dp.classid AND d.refobjid = dp.objid AND d.refobjsubid = dp.objsubid + ) + SELECT pg_describe_object(classid, objid, objsubid) as obj, + pg_identify_object(classid, objid, objsubid) as ident, + pg_identify_object_as_address(classid, objid, objsubid) as addr + FROM deps +) s +ORDER BY obj COLLATE "C", ident::text COLLATE "C"; + \a\t SELECT pg_get_propgraphdef('g2'::regclass); SELECT pg_get_propgraphdef('g3'::regclass); diff --git a/src/test/regress/sql/event_trigger.sql b/src/test/regress/sql/event_trigger.sql index 32e9bb58c5e..271f443378b 100644 --- a/src/test/regress/sql/event_trigger.sql +++ b/src/test/regress/sql/event_trigger.sql @@ -143,6 +143,19 @@ create user mapping for regress_evt_user server useless_server; alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +CREATE TABLE t2x (i int PRIMARY KEY, j text); + +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); + +DROP PROPERTY GRAPH gx; +DROP TABLE t1x, t2x; + -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; diff --git a/src/test/regress/sql/object_address.sql b/src/test/regress/sql/object_address.sql index 1bbe9457c1c..27109d421c7 100644 --- a/src/test/regress/sql/object_address.sql +++ b/src/test/regress/sql/object_address.sql @@ -67,7 +67,9 @@ DECLARE BEGIN FOR objtype IN VALUES ('toast table'), ('index column'), ('sequence column'), ('toast table column'), ('view column'), ('materialized view column'), - ('property graph element'), ('property graph label'), ('property graph property') + ('property graph element'), ('property graph element label'), + ('property graph label'), ('property graph label property'), + ('property graph property') LOOP BEGIN PERFORM pg_get_object_address(objtype, '{one}', '{}'); @@ -282,7 +284,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace -- 2.34.1 --R84XrR4Hgw0dH3Ec-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v2] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-23 09:27 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-23 09:27 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing them to hit the default case and error out with "unsupported object class". During DROP PROPERTY GRAPH, this manifests when an event trigger is active, because pg_event_trigger_ddl_commands() calls these functions. The same code paths are also reachable via pg_identify_object() and pg_identify_object_as_address(). This commit adds the missing cases. Test coverage is added in object_address.sql for these two catalog types via the zero-OID test that exercises pg_identify_object() and pg_identify_object_as_address(). A test in event_trigger.sql verifies that DROP PROPERTY GRAPH works correctly when an event trigger is active. Author: Bertrand Drouvot <[email protected]> Reviewed-by: Michael Paquier <[email protected]> Reviewed-by: Ashutosh Bapat <[email protected]> Discussion: https://postgr.es/m/aej1DkLwhyZWmtxJ@bdtpg --- src/backend/catalog/objectaddress.c | 93 ++++++++++++++++++++ src/test/regress/expected/event_trigger.out | 17 ++++ src/test/regress/expected/object_address.out | 4 + src/test/regress/sql/event_trigger.sql | 13 +++ src/test/regress/sql/object_address.sql | 2 + 5 files changed, 129 insertions(+) 62.4% src/backend/catalog/ 25.6% src/test/regress/expected/ 11.8% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/event_trigger.out b/src/test/regress/expected/event_trigger.out index 065f586310f..ed8d5df397e 100644 --- a/src/test/regress/expected/event_trigger.out +++ b/src/test/regress/expected/event_trigger.out @@ -173,6 +173,23 @@ NOTICE: test_event_trigger: ddl_command_end CREATE USER MAPPING alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; NOTICE: test_event_trigger: ddl_command_end ALTER DEFAULT PRIVILEGES +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE TABLE t2x (i int PRIMARY KEY, j text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); +NOTICE: test_event_trigger: ddl_command_end CREATE PROPERTY GRAPH +DROP PROPERTY GRAPH gx; +NOTICE: test_event_trigger: ddl_command_end DROP PROPERTY GRAPH +DROP TABLE t1x, t2x; +NOTICE: test_event_trigger: ddl_command_end DROP TABLE -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; ERROR: permission denied to change owner of event trigger "regress_event_trigger" diff --git a/src/test/regress/expected/object_address.out b/src/test/regress/expected/object_address.out index 97227d67a54..729c3537f25 100644 --- a/src/test/regress/expected/object_address.out +++ b/src/test/regress/expected/object_address.out @@ -593,7 +593,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace @@ -653,6 +655,8 @@ ORDER BY objects.classid, objects.objid, objects.objsubid; ("(""parameter ACL"",,,)")|("(""parameter ACL"",,)")|NULL ("(""property graph element"",,,)")|("(""property graph element"",,)")|NULL ("(""property graph label"",,,)")|("(""property graph label"",,)")|NULL +("(""property graph element label"",,,)")|("(""property graph element label"",,)")|NULL ("(""property graph property"",,,)")|("(""property graph property"",,)")|NULL +("(""property graph label property"",,,)")|("(""property graph label property"",,)")|NULL -- restore normal output mode \a\t diff --git a/src/test/regress/sql/event_trigger.sql b/src/test/regress/sql/event_trigger.sql index 32e9bb58c5e..271f443378b 100644 --- a/src/test/regress/sql/event_trigger.sql +++ b/src/test/regress/sql/event_trigger.sql @@ -143,6 +143,19 @@ create user mapping for regress_evt_user server useless_server; alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +CREATE TABLE t2x (i int PRIMARY KEY, j text); + +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); + +DROP PROPERTY GRAPH gx; +DROP TABLE t1x, t2x; + -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; diff --git a/src/test/regress/sql/object_address.sql b/src/test/regress/sql/object_address.sql index 1bbe9457c1c..620dacf1045 100644 --- a/src/test/regress/sql/object_address.sql +++ b/src/test/regress/sql/object_address.sql @@ -282,7 +282,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace -- 2.34.1 --gtUR827Uq8d5gVsQ-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v2] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-23 09:27 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-23 09:27 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing them to hit the default case and error out with "unsupported object class". During DROP PROPERTY GRAPH, this manifests when an event trigger is active, because pg_event_trigger_ddl_commands() calls these functions. The same code paths are also reachable via pg_identify_object() and pg_identify_object_as_address(). This commit adds the missing cases. Test coverage is added in object_address.sql for these two catalog types via the zero-OID test that exercises pg_identify_object() and pg_identify_object_as_address(). A test in event_trigger.sql verifies that DROP PROPERTY GRAPH works correctly when an event trigger is active. Author: Bertrand Drouvot <[email protected]> Reviewed-by: Michael Paquier <[email protected]> Reviewed-by: Ashutosh Bapat <[email protected]> Discussion: https://postgr.es/m/aej1DkLwhyZWmtxJ@bdtpg --- src/backend/catalog/objectaddress.c | 93 ++++++++++++++++++++ src/test/regress/expected/event_trigger.out | 17 ++++ src/test/regress/expected/object_address.out | 4 + src/test/regress/sql/event_trigger.sql | 13 +++ src/test/regress/sql/object_address.sql | 2 + 5 files changed, 129 insertions(+) 62.4% src/backend/catalog/ 25.6% src/test/regress/expected/ 11.8% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/event_trigger.out b/src/test/regress/expected/event_trigger.out index 065f586310f..ed8d5df397e 100644 --- a/src/test/regress/expected/event_trigger.out +++ b/src/test/regress/expected/event_trigger.out @@ -173,6 +173,23 @@ NOTICE: test_event_trigger: ddl_command_end CREATE USER MAPPING alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; NOTICE: test_event_trigger: ddl_command_end ALTER DEFAULT PRIVILEGES +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE TABLE t2x (i int PRIMARY KEY, j text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); +NOTICE: test_event_trigger: ddl_command_end CREATE PROPERTY GRAPH +DROP PROPERTY GRAPH gx; +NOTICE: test_event_trigger: ddl_command_end DROP PROPERTY GRAPH +DROP TABLE t1x, t2x; +NOTICE: test_event_trigger: ddl_command_end DROP TABLE -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; ERROR: permission denied to change owner of event trigger "regress_event_trigger" diff --git a/src/test/regress/expected/object_address.out b/src/test/regress/expected/object_address.out index 97227d67a54..729c3537f25 100644 --- a/src/test/regress/expected/object_address.out +++ b/src/test/regress/expected/object_address.out @@ -593,7 +593,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace @@ -653,6 +655,8 @@ ORDER BY objects.classid, objects.objid, objects.objsubid; ("(""parameter ACL"",,,)")|("(""parameter ACL"",,)")|NULL ("(""property graph element"",,,)")|("(""property graph element"",,)")|NULL ("(""property graph label"",,,)")|("(""property graph label"",,)")|NULL +("(""property graph element label"",,,)")|("(""property graph element label"",,)")|NULL ("(""property graph property"",,,)")|("(""property graph property"",,)")|NULL +("(""property graph label property"",,,)")|("(""property graph label property"",,)")|NULL -- restore normal output mode \a\t diff --git a/src/test/regress/sql/event_trigger.sql b/src/test/regress/sql/event_trigger.sql index 32e9bb58c5e..271f443378b 100644 --- a/src/test/regress/sql/event_trigger.sql +++ b/src/test/regress/sql/event_trigger.sql @@ -143,6 +143,19 @@ create user mapping for regress_evt_user server useless_server; alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +CREATE TABLE t2x (i int PRIMARY KEY, j text); + +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); + +DROP PROPERTY GRAPH gx; +DROP TABLE t1x, t2x; + -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; diff --git a/src/test/regress/sql/object_address.sql b/src/test/regress/sql/object_address.sql index 1bbe9457c1c..620dacf1045 100644 --- a/src/test/regress/sql/object_address.sql +++ b/src/test/regress/sql/object_address.sql @@ -282,7 +282,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace -- 2.34.1 --gtUR827Uq8d5gVsQ-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v2] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-23 09:27 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-23 09:27 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing them to hit the default case and error out with "unsupported object class". During DROP PROPERTY GRAPH, this manifests when an event trigger is active, because pg_event_trigger_ddl_commands() calls these functions. The same code paths are also reachable via pg_identify_object() and pg_identify_object_as_address(). This commit adds the missing cases. Test coverage is added in object_address.sql for these two catalog types via the zero-OID test that exercises pg_identify_object() and pg_identify_object_as_address(). A test in event_trigger.sql verifies that DROP PROPERTY GRAPH works correctly when an event trigger is active. Author: Bertrand Drouvot <[email protected]> Reviewed-by: Michael Paquier <[email protected]> Reviewed-by: Ashutosh Bapat <[email protected]> Discussion: https://postgr.es/m/aej1DkLwhyZWmtxJ@bdtpg --- src/backend/catalog/objectaddress.c | 93 ++++++++++++++++++++ src/test/regress/expected/event_trigger.out | 17 ++++ src/test/regress/expected/object_address.out | 4 + src/test/regress/sql/event_trigger.sql | 13 +++ src/test/regress/sql/object_address.sql | 2 + 5 files changed, 129 insertions(+) 62.4% src/backend/catalog/ 25.6% src/test/regress/expected/ 11.8% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/event_trigger.out b/src/test/regress/expected/event_trigger.out index 065f586310f..ed8d5df397e 100644 --- a/src/test/regress/expected/event_trigger.out +++ b/src/test/regress/expected/event_trigger.out @@ -173,6 +173,23 @@ NOTICE: test_event_trigger: ddl_command_end CREATE USER MAPPING alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; NOTICE: test_event_trigger: ddl_command_end ALTER DEFAULT PRIVILEGES +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE TABLE t2x (i int PRIMARY KEY, j text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); +NOTICE: test_event_trigger: ddl_command_end CREATE PROPERTY GRAPH +DROP PROPERTY GRAPH gx; +NOTICE: test_event_trigger: ddl_command_end DROP PROPERTY GRAPH +DROP TABLE t1x, t2x; +NOTICE: test_event_trigger: ddl_command_end DROP TABLE -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; ERROR: permission denied to change owner of event trigger "regress_event_trigger" diff --git a/src/test/regress/expected/object_address.out b/src/test/regress/expected/object_address.out index 97227d67a54..729c3537f25 100644 --- a/src/test/regress/expected/object_address.out +++ b/src/test/regress/expected/object_address.out @@ -593,7 +593,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace @@ -653,6 +655,8 @@ ORDER BY objects.classid, objects.objid, objects.objsubid; ("(""parameter ACL"",,,)")|("(""parameter ACL"",,)")|NULL ("(""property graph element"",,,)")|("(""property graph element"",,)")|NULL ("(""property graph label"",,,)")|("(""property graph label"",,)")|NULL +("(""property graph element label"",,,)")|("(""property graph element label"",,)")|NULL ("(""property graph property"",,,)")|("(""property graph property"",,)")|NULL +("(""property graph label property"",,,)")|("(""property graph label property"",,)")|NULL -- restore normal output mode \a\t diff --git a/src/test/regress/sql/event_trigger.sql b/src/test/regress/sql/event_trigger.sql index 32e9bb58c5e..271f443378b 100644 --- a/src/test/regress/sql/event_trigger.sql +++ b/src/test/regress/sql/event_trigger.sql @@ -143,6 +143,19 @@ create user mapping for regress_evt_user server useless_server; alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +CREATE TABLE t2x (i int PRIMARY KEY, j text); + +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); + +DROP PROPERTY GRAPH gx; +DROP TABLE t1x, t2x; + -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; diff --git a/src/test/regress/sql/object_address.sql b/src/test/regress/sql/object_address.sql index 1bbe9457c1c..620dacf1045 100644 --- a/src/test/regress/sql/object_address.sql +++ b/src/test/regress/sql/object_address.sql @@ -282,7 +282,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace -- 2.34.1 --gtUR827Uq8d5gVsQ-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v2] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-23 09:27 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-23 09:27 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing them to hit the default case and error out with "unsupported object class". During DROP PROPERTY GRAPH, this manifests when an event trigger is active, because pg_event_trigger_ddl_commands() calls these functions. The same code paths are also reachable via pg_identify_object() and pg_identify_object_as_address(). This commit adds the missing cases. Test coverage is added in object_address.sql for these two catalog types via the zero-OID test that exercises pg_identify_object() and pg_identify_object_as_address(). A test in event_trigger.sql verifies that DROP PROPERTY GRAPH works correctly when an event trigger is active. Author: Bertrand Drouvot <[email protected]> Reviewed-by: Michael Paquier <[email protected]> Reviewed-by: Ashutosh Bapat <[email protected]> Discussion: https://postgr.es/m/aej1DkLwhyZWmtxJ@bdtpg --- src/backend/catalog/objectaddress.c | 93 ++++++++++++++++++++ src/test/regress/expected/event_trigger.out | 17 ++++ src/test/regress/expected/object_address.out | 4 + src/test/regress/sql/event_trigger.sql | 13 +++ src/test/regress/sql/object_address.sql | 2 + 5 files changed, 129 insertions(+) 62.4% src/backend/catalog/ 25.6% src/test/regress/expected/ 11.8% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/event_trigger.out b/src/test/regress/expected/event_trigger.out index 065f586310f..ed8d5df397e 100644 --- a/src/test/regress/expected/event_trigger.out +++ b/src/test/regress/expected/event_trigger.out @@ -173,6 +173,23 @@ NOTICE: test_event_trigger: ddl_command_end CREATE USER MAPPING alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; NOTICE: test_event_trigger: ddl_command_end ALTER DEFAULT PRIVILEGES +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE TABLE t2x (i int PRIMARY KEY, j text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); +NOTICE: test_event_trigger: ddl_command_end CREATE PROPERTY GRAPH +DROP PROPERTY GRAPH gx; +NOTICE: test_event_trigger: ddl_command_end DROP PROPERTY GRAPH +DROP TABLE t1x, t2x; +NOTICE: test_event_trigger: ddl_command_end DROP TABLE -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; ERROR: permission denied to change owner of event trigger "regress_event_trigger" diff --git a/src/test/regress/expected/object_address.out b/src/test/regress/expected/object_address.out index 97227d67a54..729c3537f25 100644 --- a/src/test/regress/expected/object_address.out +++ b/src/test/regress/expected/object_address.out @@ -593,7 +593,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace @@ -653,6 +655,8 @@ ORDER BY objects.classid, objects.objid, objects.objsubid; ("(""parameter ACL"",,,)")|("(""parameter ACL"",,)")|NULL ("(""property graph element"",,,)")|("(""property graph element"",,)")|NULL ("(""property graph label"",,,)")|("(""property graph label"",,)")|NULL +("(""property graph element label"",,,)")|("(""property graph element label"",,)")|NULL ("(""property graph property"",,,)")|("(""property graph property"",,)")|NULL +("(""property graph label property"",,,)")|("(""property graph label property"",,)")|NULL -- restore normal output mode \a\t diff --git a/src/test/regress/sql/event_trigger.sql b/src/test/regress/sql/event_trigger.sql index 32e9bb58c5e..271f443378b 100644 --- a/src/test/regress/sql/event_trigger.sql +++ b/src/test/regress/sql/event_trigger.sql @@ -143,6 +143,19 @@ create user mapping for regress_evt_user server useless_server; alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +CREATE TABLE t2x (i int PRIMARY KEY, j text); + +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); + +DROP PROPERTY GRAPH gx; +DROP TABLE t1x, t2x; + -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; diff --git a/src/test/regress/sql/object_address.sql b/src/test/regress/sql/object_address.sql index 1bbe9457c1c..620dacf1045 100644 --- a/src/test/regress/sql/object_address.sql +++ b/src/test/regress/sql/object_address.sql @@ -282,7 +282,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace -- 2.34.1 --gtUR827Uq8d5gVsQ-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v3] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-23 09:27 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-23 09:27 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing them to hit the default case and error out with "unsupported object class". During DROP PROPERTY GRAPH, this manifests when an event trigger is active, because pg_event_trigger_ddl_commands() calls these functions. The same code paths are also reachable via pg_identify_object() and pg_identify_object_as_address(). This commit adds the missing cases. Test coverage is added in object_address.sql for these two catalog types and in create_property_graph.sql covering all property graph object types. A test in event_trigger.sql verifies that DROP PROPERTY GRAPH works correctly when an event trigger is active. Author: Bertrand Drouvot <[email protected]> Reviewed-by: Michael Paquier <[email protected]> Reviewed-by: Ashutosh Bapat <[email protected]> Discussion: https://postgr.es/m/aej1DkLwhyZWmtxJ@bdtpg --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 78 ++++++++++++++++ src/test/regress/expected/event_trigger.out | 17 ++++ src/test/regress/expected/object_address.out | 10 +- .../regress/sql/create_property_graph.sql | 23 +++++ src/test/regress/sql/event_trigger.sql | 13 +++ src/test/regress/sql/object_address.sql | 6 +- 7 files changed, 238 insertions(+), 2 deletions(-) 14.7% src/backend/catalog/ 75.5% src/test/regress/expected/ 9.7% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..eb9e17fb727 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -752,6 +752,84 @@ SELECT (pg_identify_object(classid, objid, objsubid)).* type | create_property_graph_tests | g2 | create_property_graph_tests.g2 (21 rows) +-- test object address functions with recursive dependency walk +-- covers all property graph object types including indirect dependents +SELECT * +FROM ( + WITH RECURSIVE deps (classid, objid, objsubid, refclassid, refobjid, refobjsubid) AS ( + SELECT classid, objid, objsubid, + refclassid, refobjid, refobjsubid + FROM pg_depend + WHERE refclassid = 'pg_class'::regclass AND + refobjid = 'create_property_graph_tests.gt'::regclass + UNION ALL + SELECT d.classid, d.objid, d.objsubid, + d.refclassid, d.refobjid, d.refobjsubid + FROM pg_depend d + JOIN deps dp ON d.refclassid = dp.classid AND d.refobjid = dp.objid AND d.refobjsubid = dp.objsubid + ) + SELECT pg_describe_object(classid, objid, objsubid) as obj, + pg_identify_object(classid, objid, objsubid) as ident, + pg_identify_object_as_address(classid, objid, objsubid) as addr + FROM deps +) s +ORDER BY obj COLLATE "C", ident::text COLLATE "C"; + obj | ident | addr +----------------------------------------------------------+----------------------------------------------------------------------------+---------------------------------------------------------------------------- + edge e of property graph gt | ("property graph element",,,"e of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,e}",{}) + edge e of property graph gt | ("property graph element",,,"e of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,e}",{}) + edge e of property graph gt | ("property graph element",,,"e of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of property graph gt | ("property graph label",,,"e of create_property_graph_tests.gt") | ("property graph label","{create_property_graph_tests,gt,e}",{}) + label v1 of property graph gt | ("property graph label",,,"v1 of create_property_graph_tests.gt") | ("property graph label","{create_property_graph_tests,gt,v1}",{}) + label v1 of vertex v1 of property graph gt | ("property graph element label",,,"v1 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v1}",{}) + label v1 of vertex v1 of property graph gt | ("property graph element label",,,"v1 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v1}",{}) + label v2 of property graph gt | ("property graph label",,,"v2 of create_property_graph_tests.gt") | ("property graph label","{create_property_graph_tests,gt,v2}",{}) + label v2 of vertex v2 of property graph gt | ("property graph element label",,,"v2 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v2}",{}) + label v2 of vertex v2 of property graph gt | ("property graph element label",,,"v2 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v2}",{}) + property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property a of property graph gt | ("property graph property",,,"a of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,a}",{}) + property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property b of property graph gt | ("property graph property",,,"b of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,b}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of property graph gt | ("property graph property",,,"c of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,c}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of property graph gt | ("property graph property",,,"k1 of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,k1}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of property graph gt | ("property graph property",,,"k2 of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,k2}",{}) + property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property m of property graph gt | ("property graph property",,,"m of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,m}",{}) + property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property n of property graph gt | ("property graph property",,,"n of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,n}",{}) + type gt | (type,create_property_graph_tests,gt,create_property_graph_tests.gt) | (type,{create_property_graph_tests.gt},{}) + type gt[] | (type,create_property_graph_tests,_gt,create_property_graph_tests.gt[]) | (type,{create_property_graph_tests.gt[]},{}) + vertex v1 of property graph gt | ("property graph element",,,"v1 of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,v1}",{}) + vertex v2 of property graph gt | ("property graph element",,,"v2 of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,v2}",{}) +(52 rows) + \a\t SELECT pg_get_propgraphdef('g2'::regclass); CREATE PROPERTY GRAPH create_property_graph_tests.g2 diff --git a/src/test/regress/expected/event_trigger.out b/src/test/regress/expected/event_trigger.out index 065f586310f..ed8d5df397e 100644 --- a/src/test/regress/expected/event_trigger.out +++ b/src/test/regress/expected/event_trigger.out @@ -173,6 +173,23 @@ NOTICE: test_event_trigger: ddl_command_end CREATE USER MAPPING alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; NOTICE: test_event_trigger: ddl_command_end ALTER DEFAULT PRIVILEGES +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE TABLE t2x (i int PRIMARY KEY, j text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); +NOTICE: test_event_trigger: ddl_command_end CREATE PROPERTY GRAPH +DROP PROPERTY GRAPH gx; +NOTICE: test_event_trigger: ddl_command_end DROP PROPERTY GRAPH +DROP TABLE t1x, t2x; +NOTICE: test_event_trigger: ddl_command_end DROP TABLE -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; ERROR: permission denied to change owner of event trigger "regress_event_trigger" diff --git a/src/test/regress/expected/object_address.out b/src/test/regress/expected/object_address.out index 97227d67a54..5e53f0b092e 100644 --- a/src/test/regress/expected/object_address.out +++ b/src/test/regress/expected/object_address.out @@ -67,7 +67,9 @@ DECLARE BEGIN FOR objtype IN VALUES ('toast table'), ('index column'), ('sequence column'), ('toast table column'), ('view column'), ('materialized view column'), - ('property graph element'), ('property graph label'), ('property graph property') + ('property graph element'), ('property graph element label'), + ('property graph label'), ('property graph label property'), + ('property graph property') LOOP BEGIN PERFORM pg_get_object_address(objtype, '{one}', '{}'); @@ -84,7 +86,9 @@ WARNING: error for toast table column: unsupported object type "toast table col WARNING: error for view column: unsupported object type "view column" WARNING: error for materialized view column: unsupported object type "materialized view column" WARNING: error for property graph element: unsupported object type "property graph element" +WARNING: error for property graph element label: unrecognized object type "property graph element label" WARNING: error for property graph label: unsupported object type "property graph label" +WARNING: error for property graph label property: unrecognized object type "property graph label property" WARNING: error for property graph property: unsupported object type "property graph property" -- miscellaneous other errors select * from pg_get_object_address('operator of access method', '{btree,integer_ops,1}', '{int4,bool}'); @@ -593,7 +597,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace @@ -653,6 +659,8 @@ ORDER BY objects.classid, objects.objid, objects.objsubid; ("(""parameter ACL"",,,)")|("(""parameter ACL"",,)")|NULL ("(""property graph element"",,,)")|("(""property graph element"",,)")|NULL ("(""property graph label"",,,)")|("(""property graph label"",,)")|NULL +("(""property graph element label"",,,)")|("(""property graph element label"",,)")|NULL ("(""property graph property"",,,)")|("(""property graph property"",,)")|NULL +("(""property graph label property"",,,)")|("(""property graph label property"",,)")|NULL -- restore normal output mode \a\t diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..9608dd5c4af 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -298,6 +298,29 @@ SELECT (pg_identify_object(classid, objid, objsubid)).* refobjid = 'create_property_graph_tests.g2'::regclass ORDER BY 1, 2, 3, 4; +-- test object address functions with recursive dependency walk +-- covers all property graph object types including indirect dependents +SELECT * +FROM ( + WITH RECURSIVE deps (classid, objid, objsubid, refclassid, refobjid, refobjsubid) AS ( + SELECT classid, objid, objsubid, + refclassid, refobjid, refobjsubid + FROM pg_depend + WHERE refclassid = 'pg_class'::regclass AND + refobjid = 'create_property_graph_tests.gt'::regclass + UNION ALL + SELECT d.classid, d.objid, d.objsubid, + d.refclassid, d.refobjid, d.refobjsubid + FROM pg_depend d + JOIN deps dp ON d.refclassid = dp.classid AND d.refobjid = dp.objid AND d.refobjsubid = dp.objsubid + ) + SELECT pg_describe_object(classid, objid, objsubid) as obj, + pg_identify_object(classid, objid, objsubid) as ident, + pg_identify_object_as_address(classid, objid, objsubid) as addr + FROM deps +) s +ORDER BY obj COLLATE "C", ident::text COLLATE "C"; + \a\t SELECT pg_get_propgraphdef('g2'::regclass); SELECT pg_get_propgraphdef('g3'::regclass); diff --git a/src/test/regress/sql/event_trigger.sql b/src/test/regress/sql/event_trigger.sql index 32e9bb58c5e..271f443378b 100644 --- a/src/test/regress/sql/event_trigger.sql +++ b/src/test/regress/sql/event_trigger.sql @@ -143,6 +143,19 @@ create user mapping for regress_evt_user server useless_server; alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +CREATE TABLE t2x (i int PRIMARY KEY, j text); + +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); + +DROP PROPERTY GRAPH gx; +DROP TABLE t1x, t2x; + -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; diff --git a/src/test/regress/sql/object_address.sql b/src/test/regress/sql/object_address.sql index 1bbe9457c1c..27109d421c7 100644 --- a/src/test/regress/sql/object_address.sql +++ b/src/test/regress/sql/object_address.sql @@ -67,7 +67,9 @@ DECLARE BEGIN FOR objtype IN VALUES ('toast table'), ('index column'), ('sequence column'), ('toast table column'), ('view column'), ('materialized view column'), - ('property graph element'), ('property graph label'), ('property graph property') + ('property graph element'), ('property graph element label'), + ('property graph label'), ('property graph label property'), + ('property graph property') LOOP BEGIN PERFORM pg_get_object_address(objtype, '{one}', '{}'); @@ -282,7 +284,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace -- 2.34.1 --R84XrR4Hgw0dH3Ec-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v3] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-23 09:27 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-23 09:27 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing them to hit the default case and error out with "unsupported object class". During DROP PROPERTY GRAPH, this manifests when an event trigger is active, because pg_event_trigger_ddl_commands() calls these functions. The same code paths are also reachable via pg_identify_object() and pg_identify_object_as_address(). This commit adds the missing cases. Test coverage is added in object_address.sql for these two catalog types and in create_property_graph.sql covering all property graph object types. A test in event_trigger.sql verifies that DROP PROPERTY GRAPH works correctly when an event trigger is active. Author: Bertrand Drouvot <[email protected]> Reviewed-by: Michael Paquier <[email protected]> Reviewed-by: Ashutosh Bapat <[email protected]> Discussion: https://postgr.es/m/aej1DkLwhyZWmtxJ@bdtpg --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 78 ++++++++++++++++ src/test/regress/expected/event_trigger.out | 17 ++++ src/test/regress/expected/object_address.out | 10 +- .../regress/sql/create_property_graph.sql | 23 +++++ src/test/regress/sql/event_trigger.sql | 13 +++ src/test/regress/sql/object_address.sql | 6 +- 7 files changed, 238 insertions(+), 2 deletions(-) 14.7% src/backend/catalog/ 75.5% src/test/regress/expected/ 9.7% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..eb9e17fb727 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -752,6 +752,84 @@ SELECT (pg_identify_object(classid, objid, objsubid)).* type | create_property_graph_tests | g2 | create_property_graph_tests.g2 (21 rows) +-- test object address functions with recursive dependency walk +-- covers all property graph object types including indirect dependents +SELECT * +FROM ( + WITH RECURSIVE deps (classid, objid, objsubid, refclassid, refobjid, refobjsubid) AS ( + SELECT classid, objid, objsubid, + refclassid, refobjid, refobjsubid + FROM pg_depend + WHERE refclassid = 'pg_class'::regclass AND + refobjid = 'create_property_graph_tests.gt'::regclass + UNION ALL + SELECT d.classid, d.objid, d.objsubid, + d.refclassid, d.refobjid, d.refobjsubid + FROM pg_depend d + JOIN deps dp ON d.refclassid = dp.classid AND d.refobjid = dp.objid AND d.refobjsubid = dp.objsubid + ) + SELECT pg_describe_object(classid, objid, objsubid) as obj, + pg_identify_object(classid, objid, objsubid) as ident, + pg_identify_object_as_address(classid, objid, objsubid) as addr + FROM deps +) s +ORDER BY obj COLLATE "C", ident::text COLLATE "C"; + obj | ident | addr +----------------------------------------------------------+----------------------------------------------------------------------------+---------------------------------------------------------------------------- + edge e of property graph gt | ("property graph element",,,"e of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,e}",{}) + edge e of property graph gt | ("property graph element",,,"e of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,e}",{}) + edge e of property graph gt | ("property graph element",,,"e of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of property graph gt | ("property graph label",,,"e of create_property_graph_tests.gt") | ("property graph label","{create_property_graph_tests,gt,e}",{}) + label v1 of property graph gt | ("property graph label",,,"v1 of create_property_graph_tests.gt") | ("property graph label","{create_property_graph_tests,gt,v1}",{}) + label v1 of vertex v1 of property graph gt | ("property graph element label",,,"v1 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v1}",{}) + label v1 of vertex v1 of property graph gt | ("property graph element label",,,"v1 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v1}",{}) + label v2 of property graph gt | ("property graph label",,,"v2 of create_property_graph_tests.gt") | ("property graph label","{create_property_graph_tests,gt,v2}",{}) + label v2 of vertex v2 of property graph gt | ("property graph element label",,,"v2 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v2}",{}) + label v2 of vertex v2 of property graph gt | ("property graph element label",,,"v2 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v2}",{}) + property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property a of property graph gt | ("property graph property",,,"a of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,a}",{}) + property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property b of property graph gt | ("property graph property",,,"b of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,b}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of property graph gt | ("property graph property",,,"c of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,c}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of property graph gt | ("property graph property",,,"k1 of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,k1}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of property graph gt | ("property graph property",,,"k2 of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,k2}",{}) + property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property m of property graph gt | ("property graph property",,,"m of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,m}",{}) + property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property n of property graph gt | ("property graph property",,,"n of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,n}",{}) + type gt | (type,create_property_graph_tests,gt,create_property_graph_tests.gt) | (type,{create_property_graph_tests.gt},{}) + type gt[] | (type,create_property_graph_tests,_gt,create_property_graph_tests.gt[]) | (type,{create_property_graph_tests.gt[]},{}) + vertex v1 of property graph gt | ("property graph element",,,"v1 of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,v1}",{}) + vertex v2 of property graph gt | ("property graph element",,,"v2 of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,v2}",{}) +(52 rows) + \a\t SELECT pg_get_propgraphdef('g2'::regclass); CREATE PROPERTY GRAPH create_property_graph_tests.g2 diff --git a/src/test/regress/expected/event_trigger.out b/src/test/regress/expected/event_trigger.out index 065f586310f..ed8d5df397e 100644 --- a/src/test/regress/expected/event_trigger.out +++ b/src/test/regress/expected/event_trigger.out @@ -173,6 +173,23 @@ NOTICE: test_event_trigger: ddl_command_end CREATE USER MAPPING alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; NOTICE: test_event_trigger: ddl_command_end ALTER DEFAULT PRIVILEGES +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE TABLE t2x (i int PRIMARY KEY, j text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); +NOTICE: test_event_trigger: ddl_command_end CREATE PROPERTY GRAPH +DROP PROPERTY GRAPH gx; +NOTICE: test_event_trigger: ddl_command_end DROP PROPERTY GRAPH +DROP TABLE t1x, t2x; +NOTICE: test_event_trigger: ddl_command_end DROP TABLE -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; ERROR: permission denied to change owner of event trigger "regress_event_trigger" diff --git a/src/test/regress/expected/object_address.out b/src/test/regress/expected/object_address.out index 97227d67a54..5e53f0b092e 100644 --- a/src/test/regress/expected/object_address.out +++ b/src/test/regress/expected/object_address.out @@ -67,7 +67,9 @@ DECLARE BEGIN FOR objtype IN VALUES ('toast table'), ('index column'), ('sequence column'), ('toast table column'), ('view column'), ('materialized view column'), - ('property graph element'), ('property graph label'), ('property graph property') + ('property graph element'), ('property graph element label'), + ('property graph label'), ('property graph label property'), + ('property graph property') LOOP BEGIN PERFORM pg_get_object_address(objtype, '{one}', '{}'); @@ -84,7 +86,9 @@ WARNING: error for toast table column: unsupported object type "toast table col WARNING: error for view column: unsupported object type "view column" WARNING: error for materialized view column: unsupported object type "materialized view column" WARNING: error for property graph element: unsupported object type "property graph element" +WARNING: error for property graph element label: unrecognized object type "property graph element label" WARNING: error for property graph label: unsupported object type "property graph label" +WARNING: error for property graph label property: unrecognized object type "property graph label property" WARNING: error for property graph property: unsupported object type "property graph property" -- miscellaneous other errors select * from pg_get_object_address('operator of access method', '{btree,integer_ops,1}', '{int4,bool}'); @@ -593,7 +597,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace @@ -653,6 +659,8 @@ ORDER BY objects.classid, objects.objid, objects.objsubid; ("(""parameter ACL"",,,)")|("(""parameter ACL"",,)")|NULL ("(""property graph element"",,,)")|("(""property graph element"",,)")|NULL ("(""property graph label"",,,)")|("(""property graph label"",,)")|NULL +("(""property graph element label"",,,)")|("(""property graph element label"",,)")|NULL ("(""property graph property"",,,)")|("(""property graph property"",,)")|NULL +("(""property graph label property"",,,)")|("(""property graph label property"",,)")|NULL -- restore normal output mode \a\t diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..9608dd5c4af 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -298,6 +298,29 @@ SELECT (pg_identify_object(classid, objid, objsubid)).* refobjid = 'create_property_graph_tests.g2'::regclass ORDER BY 1, 2, 3, 4; +-- test object address functions with recursive dependency walk +-- covers all property graph object types including indirect dependents +SELECT * +FROM ( + WITH RECURSIVE deps (classid, objid, objsubid, refclassid, refobjid, refobjsubid) AS ( + SELECT classid, objid, objsubid, + refclassid, refobjid, refobjsubid + FROM pg_depend + WHERE refclassid = 'pg_class'::regclass AND + refobjid = 'create_property_graph_tests.gt'::regclass + UNION ALL + SELECT d.classid, d.objid, d.objsubid, + d.refclassid, d.refobjid, d.refobjsubid + FROM pg_depend d + JOIN deps dp ON d.refclassid = dp.classid AND d.refobjid = dp.objid AND d.refobjsubid = dp.objsubid + ) + SELECT pg_describe_object(classid, objid, objsubid) as obj, + pg_identify_object(classid, objid, objsubid) as ident, + pg_identify_object_as_address(classid, objid, objsubid) as addr + FROM deps +) s +ORDER BY obj COLLATE "C", ident::text COLLATE "C"; + \a\t SELECT pg_get_propgraphdef('g2'::regclass); SELECT pg_get_propgraphdef('g3'::regclass); diff --git a/src/test/regress/sql/event_trigger.sql b/src/test/regress/sql/event_trigger.sql index 32e9bb58c5e..271f443378b 100644 --- a/src/test/regress/sql/event_trigger.sql +++ b/src/test/regress/sql/event_trigger.sql @@ -143,6 +143,19 @@ create user mapping for regress_evt_user server useless_server; alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +CREATE TABLE t2x (i int PRIMARY KEY, j text); + +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); + +DROP PROPERTY GRAPH gx; +DROP TABLE t1x, t2x; + -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; diff --git a/src/test/regress/sql/object_address.sql b/src/test/regress/sql/object_address.sql index 1bbe9457c1c..27109d421c7 100644 --- a/src/test/regress/sql/object_address.sql +++ b/src/test/regress/sql/object_address.sql @@ -67,7 +67,9 @@ DECLARE BEGIN FOR objtype IN VALUES ('toast table'), ('index column'), ('sequence column'), ('toast table column'), ('view column'), ('materialized view column'), - ('property graph element'), ('property graph label'), ('property graph property') + ('property graph element'), ('property graph element label'), + ('property graph label'), ('property graph label property'), + ('property graph property') LOOP BEGIN PERFORM pg_get_object_address(objtype, '{one}', '{}'); @@ -282,7 +284,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace -- 2.34.1 --R84XrR4Hgw0dH3Ec-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v2] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-23 09:27 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-23 09:27 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing them to hit the default case and error out with "unsupported object class". During DROP PROPERTY GRAPH, this manifests when an event trigger is active, because pg_event_trigger_ddl_commands() calls these functions. The same code paths are also reachable via pg_identify_object() and pg_identify_object_as_address(). This commit adds the missing cases. Test coverage is added in object_address.sql for these two catalog types via the zero-OID test that exercises pg_identify_object() and pg_identify_object_as_address(). A test in event_trigger.sql verifies that DROP PROPERTY GRAPH works correctly when an event trigger is active. Author: Bertrand Drouvot <[email protected]> Reviewed-by: Michael Paquier <[email protected]> Reviewed-by: Ashutosh Bapat <[email protected]> Discussion: https://postgr.es/m/aej1DkLwhyZWmtxJ@bdtpg --- src/backend/catalog/objectaddress.c | 93 ++++++++++++++++++++ src/test/regress/expected/event_trigger.out | 17 ++++ src/test/regress/expected/object_address.out | 4 + src/test/regress/sql/event_trigger.sql | 13 +++ src/test/regress/sql/object_address.sql | 2 + 5 files changed, 129 insertions(+) 62.4% src/backend/catalog/ 25.6% src/test/regress/expected/ 11.8% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/event_trigger.out b/src/test/regress/expected/event_trigger.out index 065f586310f..ed8d5df397e 100644 --- a/src/test/regress/expected/event_trigger.out +++ b/src/test/regress/expected/event_trigger.out @@ -173,6 +173,23 @@ NOTICE: test_event_trigger: ddl_command_end CREATE USER MAPPING alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; NOTICE: test_event_trigger: ddl_command_end ALTER DEFAULT PRIVILEGES +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE TABLE t2x (i int PRIMARY KEY, j text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); +NOTICE: test_event_trigger: ddl_command_end CREATE PROPERTY GRAPH +DROP PROPERTY GRAPH gx; +NOTICE: test_event_trigger: ddl_command_end DROP PROPERTY GRAPH +DROP TABLE t1x, t2x; +NOTICE: test_event_trigger: ddl_command_end DROP TABLE -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; ERROR: permission denied to change owner of event trigger "regress_event_trigger" diff --git a/src/test/regress/expected/object_address.out b/src/test/regress/expected/object_address.out index 97227d67a54..729c3537f25 100644 --- a/src/test/regress/expected/object_address.out +++ b/src/test/regress/expected/object_address.out @@ -593,7 +593,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace @@ -653,6 +655,8 @@ ORDER BY objects.classid, objects.objid, objects.objsubid; ("(""parameter ACL"",,,)")|("(""parameter ACL"",,)")|NULL ("(""property graph element"",,,)")|("(""property graph element"",,)")|NULL ("(""property graph label"",,,)")|("(""property graph label"",,)")|NULL +("(""property graph element label"",,,)")|("(""property graph element label"",,)")|NULL ("(""property graph property"",,,)")|("(""property graph property"",,)")|NULL +("(""property graph label property"",,,)")|("(""property graph label property"",,)")|NULL -- restore normal output mode \a\t diff --git a/src/test/regress/sql/event_trigger.sql b/src/test/regress/sql/event_trigger.sql index 32e9bb58c5e..271f443378b 100644 --- a/src/test/regress/sql/event_trigger.sql +++ b/src/test/regress/sql/event_trigger.sql @@ -143,6 +143,19 @@ create user mapping for regress_evt_user server useless_server; alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +CREATE TABLE t2x (i int PRIMARY KEY, j text); + +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); + +DROP PROPERTY GRAPH gx; +DROP TABLE t1x, t2x; + -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; diff --git a/src/test/regress/sql/object_address.sql b/src/test/regress/sql/object_address.sql index 1bbe9457c1c..620dacf1045 100644 --- a/src/test/regress/sql/object_address.sql +++ b/src/test/regress/sql/object_address.sql @@ -282,7 +282,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace -- 2.34.1 --gtUR827Uq8d5gVsQ-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v2] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-23 09:27 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-23 09:27 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing them to hit the default case and error out with "unsupported object class". During DROP PROPERTY GRAPH, this manifests when an event trigger is active, because pg_event_trigger_ddl_commands() calls these functions. The same code paths are also reachable via pg_identify_object() and pg_identify_object_as_address(). This commit adds the missing cases. Test coverage is added in object_address.sql for these two catalog types via the zero-OID test that exercises pg_identify_object() and pg_identify_object_as_address(). A test in event_trigger.sql verifies that DROP PROPERTY GRAPH works correctly when an event trigger is active. Author: Bertrand Drouvot <[email protected]> Reviewed-by: Michael Paquier <[email protected]> Reviewed-by: Ashutosh Bapat <[email protected]> Discussion: https://postgr.es/m/aej1DkLwhyZWmtxJ@bdtpg --- src/backend/catalog/objectaddress.c | 93 ++++++++++++++++++++ src/test/regress/expected/event_trigger.out | 17 ++++ src/test/regress/expected/object_address.out | 4 + src/test/regress/sql/event_trigger.sql | 13 +++ src/test/regress/sql/object_address.sql | 2 + 5 files changed, 129 insertions(+) 62.4% src/backend/catalog/ 25.6% src/test/regress/expected/ 11.8% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/event_trigger.out b/src/test/regress/expected/event_trigger.out index 065f586310f..ed8d5df397e 100644 --- a/src/test/regress/expected/event_trigger.out +++ b/src/test/regress/expected/event_trigger.out @@ -173,6 +173,23 @@ NOTICE: test_event_trigger: ddl_command_end CREATE USER MAPPING alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; NOTICE: test_event_trigger: ddl_command_end ALTER DEFAULT PRIVILEGES +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE TABLE t2x (i int PRIMARY KEY, j text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); +NOTICE: test_event_trigger: ddl_command_end CREATE PROPERTY GRAPH +DROP PROPERTY GRAPH gx; +NOTICE: test_event_trigger: ddl_command_end DROP PROPERTY GRAPH +DROP TABLE t1x, t2x; +NOTICE: test_event_trigger: ddl_command_end DROP TABLE -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; ERROR: permission denied to change owner of event trigger "regress_event_trigger" diff --git a/src/test/regress/expected/object_address.out b/src/test/regress/expected/object_address.out index 97227d67a54..729c3537f25 100644 --- a/src/test/regress/expected/object_address.out +++ b/src/test/regress/expected/object_address.out @@ -593,7 +593,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace @@ -653,6 +655,8 @@ ORDER BY objects.classid, objects.objid, objects.objsubid; ("(""parameter ACL"",,,)")|("(""parameter ACL"",,)")|NULL ("(""property graph element"",,,)")|("(""property graph element"",,)")|NULL ("(""property graph label"",,,)")|("(""property graph label"",,)")|NULL +("(""property graph element label"",,,)")|("(""property graph element label"",,)")|NULL ("(""property graph property"",,,)")|("(""property graph property"",,)")|NULL +("(""property graph label property"",,,)")|("(""property graph label property"",,)")|NULL -- restore normal output mode \a\t diff --git a/src/test/regress/sql/event_trigger.sql b/src/test/regress/sql/event_trigger.sql index 32e9bb58c5e..271f443378b 100644 --- a/src/test/regress/sql/event_trigger.sql +++ b/src/test/regress/sql/event_trigger.sql @@ -143,6 +143,19 @@ create user mapping for regress_evt_user server useless_server; alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +CREATE TABLE t2x (i int PRIMARY KEY, j text); + +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); + +DROP PROPERTY GRAPH gx; +DROP TABLE t1x, t2x; + -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; diff --git a/src/test/regress/sql/object_address.sql b/src/test/regress/sql/object_address.sql index 1bbe9457c1c..620dacf1045 100644 --- a/src/test/regress/sql/object_address.sql +++ b/src/test/regress/sql/object_address.sql @@ -282,7 +282,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace -- 2.34.1 --gtUR827Uq8d5gVsQ-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v2] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-23 09:27 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-23 09:27 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing them to hit the default case and error out with "unsupported object class". During DROP PROPERTY GRAPH, this manifests when an event trigger is active, because pg_event_trigger_ddl_commands() calls these functions. The same code paths are also reachable via pg_identify_object() and pg_identify_object_as_address(). This commit adds the missing cases. Test coverage is added in object_address.sql for these two catalog types via the zero-OID test that exercises pg_identify_object() and pg_identify_object_as_address(). A test in event_trigger.sql verifies that DROP PROPERTY GRAPH works correctly when an event trigger is active. Author: Bertrand Drouvot <[email protected]> Reviewed-by: Michael Paquier <[email protected]> Reviewed-by: Ashutosh Bapat <[email protected]> Discussion: https://postgr.es/m/aej1DkLwhyZWmtxJ@bdtpg --- src/backend/catalog/objectaddress.c | 93 ++++++++++++++++++++ src/test/regress/expected/event_trigger.out | 17 ++++ src/test/regress/expected/object_address.out | 4 + src/test/regress/sql/event_trigger.sql | 13 +++ src/test/regress/sql/object_address.sql | 2 + 5 files changed, 129 insertions(+) 62.4% src/backend/catalog/ 25.6% src/test/regress/expected/ 11.8% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/event_trigger.out b/src/test/regress/expected/event_trigger.out index 065f586310f..ed8d5df397e 100644 --- a/src/test/regress/expected/event_trigger.out +++ b/src/test/regress/expected/event_trigger.out @@ -173,6 +173,23 @@ NOTICE: test_event_trigger: ddl_command_end CREATE USER MAPPING alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; NOTICE: test_event_trigger: ddl_command_end ALTER DEFAULT PRIVILEGES +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE TABLE t2x (i int PRIMARY KEY, j text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); +NOTICE: test_event_trigger: ddl_command_end CREATE PROPERTY GRAPH +DROP PROPERTY GRAPH gx; +NOTICE: test_event_trigger: ddl_command_end DROP PROPERTY GRAPH +DROP TABLE t1x, t2x; +NOTICE: test_event_trigger: ddl_command_end DROP TABLE -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; ERROR: permission denied to change owner of event trigger "regress_event_trigger" diff --git a/src/test/regress/expected/object_address.out b/src/test/regress/expected/object_address.out index 97227d67a54..729c3537f25 100644 --- a/src/test/regress/expected/object_address.out +++ b/src/test/regress/expected/object_address.out @@ -593,7 +593,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace @@ -653,6 +655,8 @@ ORDER BY objects.classid, objects.objid, objects.objsubid; ("(""parameter ACL"",,,)")|("(""parameter ACL"",,)")|NULL ("(""property graph element"",,,)")|("(""property graph element"",,)")|NULL ("(""property graph label"",,,)")|("(""property graph label"",,)")|NULL +("(""property graph element label"",,,)")|("(""property graph element label"",,)")|NULL ("(""property graph property"",,,)")|("(""property graph property"",,)")|NULL +("(""property graph label property"",,,)")|("(""property graph label property"",,)")|NULL -- restore normal output mode \a\t diff --git a/src/test/regress/sql/event_trigger.sql b/src/test/regress/sql/event_trigger.sql index 32e9bb58c5e..271f443378b 100644 --- a/src/test/regress/sql/event_trigger.sql +++ b/src/test/regress/sql/event_trigger.sql @@ -143,6 +143,19 @@ create user mapping for regress_evt_user server useless_server; alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +CREATE TABLE t2x (i int PRIMARY KEY, j text); + +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); + +DROP PROPERTY GRAPH gx; +DROP TABLE t1x, t2x; + -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; diff --git a/src/test/regress/sql/object_address.sql b/src/test/regress/sql/object_address.sql index 1bbe9457c1c..620dacf1045 100644 --- a/src/test/regress/sql/object_address.sql +++ b/src/test/regress/sql/object_address.sql @@ -282,7 +282,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace -- 2.34.1 --gtUR827Uq8d5gVsQ-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v2] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-23 09:27 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-23 09:27 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing them to hit the default case and error out with "unsupported object class". During DROP PROPERTY GRAPH, this manifests when an event trigger is active, because pg_event_trigger_ddl_commands() calls these functions. The same code paths are also reachable via pg_identify_object() and pg_identify_object_as_address(). This commit adds the missing cases. Test coverage is added in object_address.sql for these two catalog types via the zero-OID test that exercises pg_identify_object() and pg_identify_object_as_address(). A test in event_trigger.sql verifies that DROP PROPERTY GRAPH works correctly when an event trigger is active. Author: Bertrand Drouvot <[email protected]> Reviewed-by: Michael Paquier <[email protected]> Reviewed-by: Ashutosh Bapat <[email protected]> Discussion: https://postgr.es/m/aej1DkLwhyZWmtxJ@bdtpg --- src/backend/catalog/objectaddress.c | 93 ++++++++++++++++++++ src/test/regress/expected/event_trigger.out | 17 ++++ src/test/regress/expected/object_address.out | 4 + src/test/regress/sql/event_trigger.sql | 13 +++ src/test/regress/sql/object_address.sql | 2 + 5 files changed, 129 insertions(+) 62.4% src/backend/catalog/ 25.6% src/test/regress/expected/ 11.8% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/event_trigger.out b/src/test/regress/expected/event_trigger.out index 065f586310f..ed8d5df397e 100644 --- a/src/test/regress/expected/event_trigger.out +++ b/src/test/regress/expected/event_trigger.out @@ -173,6 +173,23 @@ NOTICE: test_event_trigger: ddl_command_end CREATE USER MAPPING alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; NOTICE: test_event_trigger: ddl_command_end ALTER DEFAULT PRIVILEGES +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE TABLE t2x (i int PRIMARY KEY, j text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); +NOTICE: test_event_trigger: ddl_command_end CREATE PROPERTY GRAPH +DROP PROPERTY GRAPH gx; +NOTICE: test_event_trigger: ddl_command_end DROP PROPERTY GRAPH +DROP TABLE t1x, t2x; +NOTICE: test_event_trigger: ddl_command_end DROP TABLE -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; ERROR: permission denied to change owner of event trigger "regress_event_trigger" diff --git a/src/test/regress/expected/object_address.out b/src/test/regress/expected/object_address.out index 97227d67a54..729c3537f25 100644 --- a/src/test/regress/expected/object_address.out +++ b/src/test/regress/expected/object_address.out @@ -593,7 +593,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace @@ -653,6 +655,8 @@ ORDER BY objects.classid, objects.objid, objects.objsubid; ("(""parameter ACL"",,,)")|("(""parameter ACL"",,)")|NULL ("(""property graph element"",,,)")|("(""property graph element"",,)")|NULL ("(""property graph label"",,,)")|("(""property graph label"",,)")|NULL +("(""property graph element label"",,,)")|("(""property graph element label"",,)")|NULL ("(""property graph property"",,,)")|("(""property graph property"",,)")|NULL +("(""property graph label property"",,,)")|("(""property graph label property"",,)")|NULL -- restore normal output mode \a\t diff --git a/src/test/regress/sql/event_trigger.sql b/src/test/regress/sql/event_trigger.sql index 32e9bb58c5e..271f443378b 100644 --- a/src/test/regress/sql/event_trigger.sql +++ b/src/test/regress/sql/event_trigger.sql @@ -143,6 +143,19 @@ create user mapping for regress_evt_user server useless_server; alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +CREATE TABLE t2x (i int PRIMARY KEY, j text); + +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); + +DROP PROPERTY GRAPH gx; +DROP TABLE t1x, t2x; + -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; diff --git a/src/test/regress/sql/object_address.sql b/src/test/regress/sql/object_address.sql index 1bbe9457c1c..620dacf1045 100644 --- a/src/test/regress/sql/object_address.sql +++ b/src/test/regress/sql/object_address.sql @@ -282,7 +282,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace -- 2.34.1 --gtUR827Uq8d5gVsQ-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v3] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-23 09:27 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-23 09:27 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing them to hit the default case and error out with "unsupported object class". During DROP PROPERTY GRAPH, this manifests when an event trigger is active, because pg_event_trigger_ddl_commands() calls these functions. The same code paths are also reachable via pg_identify_object() and pg_identify_object_as_address(). This commit adds the missing cases. Test coverage is added in object_address.sql for these two catalog types and in create_property_graph.sql covering all property graph object types. A test in event_trigger.sql verifies that DROP PROPERTY GRAPH works correctly when an event trigger is active. Author: Bertrand Drouvot <[email protected]> Reviewed-by: Michael Paquier <[email protected]> Reviewed-by: Ashutosh Bapat <[email protected]> Discussion: https://postgr.es/m/aej1DkLwhyZWmtxJ@bdtpg --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 78 ++++++++++++++++ src/test/regress/expected/event_trigger.out | 17 ++++ src/test/regress/expected/object_address.out | 10 +- .../regress/sql/create_property_graph.sql | 23 +++++ src/test/regress/sql/event_trigger.sql | 13 +++ src/test/regress/sql/object_address.sql | 6 +- 7 files changed, 238 insertions(+), 2 deletions(-) 14.7% src/backend/catalog/ 75.5% src/test/regress/expected/ 9.7% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..eb9e17fb727 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -752,6 +752,84 @@ SELECT (pg_identify_object(classid, objid, objsubid)).* type | create_property_graph_tests | g2 | create_property_graph_tests.g2 (21 rows) +-- test object address functions with recursive dependency walk +-- covers all property graph object types including indirect dependents +SELECT * +FROM ( + WITH RECURSIVE deps (classid, objid, objsubid, refclassid, refobjid, refobjsubid) AS ( + SELECT classid, objid, objsubid, + refclassid, refobjid, refobjsubid + FROM pg_depend + WHERE refclassid = 'pg_class'::regclass AND + refobjid = 'create_property_graph_tests.gt'::regclass + UNION ALL + SELECT d.classid, d.objid, d.objsubid, + d.refclassid, d.refobjid, d.refobjsubid + FROM pg_depend d + JOIN deps dp ON d.refclassid = dp.classid AND d.refobjid = dp.objid AND d.refobjsubid = dp.objsubid + ) + SELECT pg_describe_object(classid, objid, objsubid) as obj, + pg_identify_object(classid, objid, objsubid) as ident, + pg_identify_object_as_address(classid, objid, objsubid) as addr + FROM deps +) s +ORDER BY obj COLLATE "C", ident::text COLLATE "C"; + obj | ident | addr +----------------------------------------------------------+----------------------------------------------------------------------------+---------------------------------------------------------------------------- + edge e of property graph gt | ("property graph element",,,"e of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,e}",{}) + edge e of property graph gt | ("property graph element",,,"e of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,e}",{}) + edge e of property graph gt | ("property graph element",,,"e of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of property graph gt | ("property graph label",,,"e of create_property_graph_tests.gt") | ("property graph label","{create_property_graph_tests,gt,e}",{}) + label v1 of property graph gt | ("property graph label",,,"v1 of create_property_graph_tests.gt") | ("property graph label","{create_property_graph_tests,gt,v1}",{}) + label v1 of vertex v1 of property graph gt | ("property graph element label",,,"v1 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v1}",{}) + label v1 of vertex v1 of property graph gt | ("property graph element label",,,"v1 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v1}",{}) + label v2 of property graph gt | ("property graph label",,,"v2 of create_property_graph_tests.gt") | ("property graph label","{create_property_graph_tests,gt,v2}",{}) + label v2 of vertex v2 of property graph gt | ("property graph element label",,,"v2 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v2}",{}) + label v2 of vertex v2 of property graph gt | ("property graph element label",,,"v2 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v2}",{}) + property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property a of property graph gt | ("property graph property",,,"a of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,a}",{}) + property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property b of property graph gt | ("property graph property",,,"b of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,b}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of property graph gt | ("property graph property",,,"c of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,c}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of property graph gt | ("property graph property",,,"k1 of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,k1}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of property graph gt | ("property graph property",,,"k2 of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,k2}",{}) + property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property m of property graph gt | ("property graph property",,,"m of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,m}",{}) + property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property n of property graph gt | ("property graph property",,,"n of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,n}",{}) + type gt | (type,create_property_graph_tests,gt,create_property_graph_tests.gt) | (type,{create_property_graph_tests.gt},{}) + type gt[] | (type,create_property_graph_tests,_gt,create_property_graph_tests.gt[]) | (type,{create_property_graph_tests.gt[]},{}) + vertex v1 of property graph gt | ("property graph element",,,"v1 of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,v1}",{}) + vertex v2 of property graph gt | ("property graph element",,,"v2 of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,v2}",{}) +(52 rows) + \a\t SELECT pg_get_propgraphdef('g2'::regclass); CREATE PROPERTY GRAPH create_property_graph_tests.g2 diff --git a/src/test/regress/expected/event_trigger.out b/src/test/regress/expected/event_trigger.out index 065f586310f..ed8d5df397e 100644 --- a/src/test/regress/expected/event_trigger.out +++ b/src/test/regress/expected/event_trigger.out @@ -173,6 +173,23 @@ NOTICE: test_event_trigger: ddl_command_end CREATE USER MAPPING alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; NOTICE: test_event_trigger: ddl_command_end ALTER DEFAULT PRIVILEGES +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE TABLE t2x (i int PRIMARY KEY, j text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); +NOTICE: test_event_trigger: ddl_command_end CREATE PROPERTY GRAPH +DROP PROPERTY GRAPH gx; +NOTICE: test_event_trigger: ddl_command_end DROP PROPERTY GRAPH +DROP TABLE t1x, t2x; +NOTICE: test_event_trigger: ddl_command_end DROP TABLE -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; ERROR: permission denied to change owner of event trigger "regress_event_trigger" diff --git a/src/test/regress/expected/object_address.out b/src/test/regress/expected/object_address.out index 97227d67a54..5e53f0b092e 100644 --- a/src/test/regress/expected/object_address.out +++ b/src/test/regress/expected/object_address.out @@ -67,7 +67,9 @@ DECLARE BEGIN FOR objtype IN VALUES ('toast table'), ('index column'), ('sequence column'), ('toast table column'), ('view column'), ('materialized view column'), - ('property graph element'), ('property graph label'), ('property graph property') + ('property graph element'), ('property graph element label'), + ('property graph label'), ('property graph label property'), + ('property graph property') LOOP BEGIN PERFORM pg_get_object_address(objtype, '{one}', '{}'); @@ -84,7 +86,9 @@ WARNING: error for toast table column: unsupported object type "toast table col WARNING: error for view column: unsupported object type "view column" WARNING: error for materialized view column: unsupported object type "materialized view column" WARNING: error for property graph element: unsupported object type "property graph element" +WARNING: error for property graph element label: unrecognized object type "property graph element label" WARNING: error for property graph label: unsupported object type "property graph label" +WARNING: error for property graph label property: unrecognized object type "property graph label property" WARNING: error for property graph property: unsupported object type "property graph property" -- miscellaneous other errors select * from pg_get_object_address('operator of access method', '{btree,integer_ops,1}', '{int4,bool}'); @@ -593,7 +597,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace @@ -653,6 +659,8 @@ ORDER BY objects.classid, objects.objid, objects.objsubid; ("(""parameter ACL"",,,)")|("(""parameter ACL"",,)")|NULL ("(""property graph element"",,,)")|("(""property graph element"",,)")|NULL ("(""property graph label"",,,)")|("(""property graph label"",,)")|NULL +("(""property graph element label"",,,)")|("(""property graph element label"",,)")|NULL ("(""property graph property"",,,)")|("(""property graph property"",,)")|NULL +("(""property graph label property"",,,)")|("(""property graph label property"",,)")|NULL -- restore normal output mode \a\t diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..9608dd5c4af 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -298,6 +298,29 @@ SELECT (pg_identify_object(classid, objid, objsubid)).* refobjid = 'create_property_graph_tests.g2'::regclass ORDER BY 1, 2, 3, 4; +-- test object address functions with recursive dependency walk +-- covers all property graph object types including indirect dependents +SELECT * +FROM ( + WITH RECURSIVE deps (classid, objid, objsubid, refclassid, refobjid, refobjsubid) AS ( + SELECT classid, objid, objsubid, + refclassid, refobjid, refobjsubid + FROM pg_depend + WHERE refclassid = 'pg_class'::regclass AND + refobjid = 'create_property_graph_tests.gt'::regclass + UNION ALL + SELECT d.classid, d.objid, d.objsubid, + d.refclassid, d.refobjid, d.refobjsubid + FROM pg_depend d + JOIN deps dp ON d.refclassid = dp.classid AND d.refobjid = dp.objid AND d.refobjsubid = dp.objsubid + ) + SELECT pg_describe_object(classid, objid, objsubid) as obj, + pg_identify_object(classid, objid, objsubid) as ident, + pg_identify_object_as_address(classid, objid, objsubid) as addr + FROM deps +) s +ORDER BY obj COLLATE "C", ident::text COLLATE "C"; + \a\t SELECT pg_get_propgraphdef('g2'::regclass); SELECT pg_get_propgraphdef('g3'::regclass); diff --git a/src/test/regress/sql/event_trigger.sql b/src/test/regress/sql/event_trigger.sql index 32e9bb58c5e..271f443378b 100644 --- a/src/test/regress/sql/event_trigger.sql +++ b/src/test/regress/sql/event_trigger.sql @@ -143,6 +143,19 @@ create user mapping for regress_evt_user server useless_server; alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +CREATE TABLE t2x (i int PRIMARY KEY, j text); + +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); + +DROP PROPERTY GRAPH gx; +DROP TABLE t1x, t2x; + -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; diff --git a/src/test/regress/sql/object_address.sql b/src/test/regress/sql/object_address.sql index 1bbe9457c1c..27109d421c7 100644 --- a/src/test/regress/sql/object_address.sql +++ b/src/test/regress/sql/object_address.sql @@ -67,7 +67,9 @@ DECLARE BEGIN FOR objtype IN VALUES ('toast table'), ('index column'), ('sequence column'), ('toast table column'), ('view column'), ('materialized view column'), - ('property graph element'), ('property graph label'), ('property graph property') + ('property graph element'), ('property graph element label'), + ('property graph label'), ('property graph label property'), + ('property graph property') LOOP BEGIN PERFORM pg_get_object_address(objtype, '{one}', '{}'); @@ -282,7 +284,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace -- 2.34.1 --R84XrR4Hgw0dH3Ec-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v2] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-23 09:27 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-23 09:27 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing them to hit the default case and error out with "unsupported object class". During DROP PROPERTY GRAPH, this manifests when an event trigger is active, because pg_event_trigger_ddl_commands() calls these functions. The same code paths are also reachable via pg_identify_object() and pg_identify_object_as_address(). This commit adds the missing cases. Test coverage is added in object_address.sql for these two catalog types via the zero-OID test that exercises pg_identify_object() and pg_identify_object_as_address(). A test in event_trigger.sql verifies that DROP PROPERTY GRAPH works correctly when an event trigger is active. Author: Bertrand Drouvot <[email protected]> Reviewed-by: Michael Paquier <[email protected]> Reviewed-by: Ashutosh Bapat <[email protected]> Discussion: https://postgr.es/m/aej1DkLwhyZWmtxJ@bdtpg --- src/backend/catalog/objectaddress.c | 93 ++++++++++++++++++++ src/test/regress/expected/event_trigger.out | 17 ++++ src/test/regress/expected/object_address.out | 4 + src/test/regress/sql/event_trigger.sql | 13 +++ src/test/regress/sql/object_address.sql | 2 + 5 files changed, 129 insertions(+) 62.4% src/backend/catalog/ 25.6% src/test/regress/expected/ 11.8% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/event_trigger.out b/src/test/regress/expected/event_trigger.out index 065f586310f..ed8d5df397e 100644 --- a/src/test/regress/expected/event_trigger.out +++ b/src/test/regress/expected/event_trigger.out @@ -173,6 +173,23 @@ NOTICE: test_event_trigger: ddl_command_end CREATE USER MAPPING alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; NOTICE: test_event_trigger: ddl_command_end ALTER DEFAULT PRIVILEGES +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE TABLE t2x (i int PRIMARY KEY, j text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); +NOTICE: test_event_trigger: ddl_command_end CREATE PROPERTY GRAPH +DROP PROPERTY GRAPH gx; +NOTICE: test_event_trigger: ddl_command_end DROP PROPERTY GRAPH +DROP TABLE t1x, t2x; +NOTICE: test_event_trigger: ddl_command_end DROP TABLE -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; ERROR: permission denied to change owner of event trigger "regress_event_trigger" diff --git a/src/test/regress/expected/object_address.out b/src/test/regress/expected/object_address.out index 97227d67a54..729c3537f25 100644 --- a/src/test/regress/expected/object_address.out +++ b/src/test/regress/expected/object_address.out @@ -593,7 +593,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace @@ -653,6 +655,8 @@ ORDER BY objects.classid, objects.objid, objects.objsubid; ("(""parameter ACL"",,,)")|("(""parameter ACL"",,)")|NULL ("(""property graph element"",,,)")|("(""property graph element"",,)")|NULL ("(""property graph label"",,,)")|("(""property graph label"",,)")|NULL +("(""property graph element label"",,,)")|("(""property graph element label"",,)")|NULL ("(""property graph property"",,,)")|("(""property graph property"",,)")|NULL +("(""property graph label property"",,,)")|("(""property graph label property"",,)")|NULL -- restore normal output mode \a\t diff --git a/src/test/regress/sql/event_trigger.sql b/src/test/regress/sql/event_trigger.sql index 32e9bb58c5e..271f443378b 100644 --- a/src/test/regress/sql/event_trigger.sql +++ b/src/test/regress/sql/event_trigger.sql @@ -143,6 +143,19 @@ create user mapping for regress_evt_user server useless_server; alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +CREATE TABLE t2x (i int PRIMARY KEY, j text); + +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); + +DROP PROPERTY GRAPH gx; +DROP TABLE t1x, t2x; + -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; diff --git a/src/test/regress/sql/object_address.sql b/src/test/regress/sql/object_address.sql index 1bbe9457c1c..620dacf1045 100644 --- a/src/test/regress/sql/object_address.sql +++ b/src/test/regress/sql/object_address.sql @@ -282,7 +282,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace -- 2.34.1 --gtUR827Uq8d5gVsQ-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v3] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-23 09:27 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-23 09:27 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing them to hit the default case and error out with "unsupported object class". During DROP PROPERTY GRAPH, this manifests when an event trigger is active, because pg_event_trigger_ddl_commands() calls these functions. The same code paths are also reachable via pg_identify_object() and pg_identify_object_as_address(). This commit adds the missing cases. Test coverage is added in object_address.sql for these two catalog types and in create_property_graph.sql covering all property graph object types. A test in event_trigger.sql verifies that DROP PROPERTY GRAPH works correctly when an event trigger is active. Author: Bertrand Drouvot <[email protected]> Reviewed-by: Michael Paquier <[email protected]> Reviewed-by: Ashutosh Bapat <[email protected]> Discussion: https://postgr.es/m/aej1DkLwhyZWmtxJ@bdtpg --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 78 ++++++++++++++++ src/test/regress/expected/event_trigger.out | 17 ++++ src/test/regress/expected/object_address.out | 10 +- .../regress/sql/create_property_graph.sql | 23 +++++ src/test/regress/sql/event_trigger.sql | 13 +++ src/test/regress/sql/object_address.sql | 6 +- 7 files changed, 238 insertions(+), 2 deletions(-) 14.7% src/backend/catalog/ 75.5% src/test/regress/expected/ 9.7% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..eb9e17fb727 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -752,6 +752,84 @@ SELECT (pg_identify_object(classid, objid, objsubid)).* type | create_property_graph_tests | g2 | create_property_graph_tests.g2 (21 rows) +-- test object address functions with recursive dependency walk +-- covers all property graph object types including indirect dependents +SELECT * +FROM ( + WITH RECURSIVE deps (classid, objid, objsubid, refclassid, refobjid, refobjsubid) AS ( + SELECT classid, objid, objsubid, + refclassid, refobjid, refobjsubid + FROM pg_depend + WHERE refclassid = 'pg_class'::regclass AND + refobjid = 'create_property_graph_tests.gt'::regclass + UNION ALL + SELECT d.classid, d.objid, d.objsubid, + d.refclassid, d.refobjid, d.refobjsubid + FROM pg_depend d + JOIN deps dp ON d.refclassid = dp.classid AND d.refobjid = dp.objid AND d.refobjsubid = dp.objsubid + ) + SELECT pg_describe_object(classid, objid, objsubid) as obj, + pg_identify_object(classid, objid, objsubid) as ident, + pg_identify_object_as_address(classid, objid, objsubid) as addr + FROM deps +) s +ORDER BY obj COLLATE "C", ident::text COLLATE "C"; + obj | ident | addr +----------------------------------------------------------+----------------------------------------------------------------------------+---------------------------------------------------------------------------- + edge e of property graph gt | ("property graph element",,,"e of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,e}",{}) + edge e of property graph gt | ("property graph element",,,"e of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,e}",{}) + edge e of property graph gt | ("property graph element",,,"e of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of property graph gt | ("property graph label",,,"e of create_property_graph_tests.gt") | ("property graph label","{create_property_graph_tests,gt,e}",{}) + label v1 of property graph gt | ("property graph label",,,"v1 of create_property_graph_tests.gt") | ("property graph label","{create_property_graph_tests,gt,v1}",{}) + label v1 of vertex v1 of property graph gt | ("property graph element label",,,"v1 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v1}",{}) + label v1 of vertex v1 of property graph gt | ("property graph element label",,,"v1 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v1}",{}) + label v2 of property graph gt | ("property graph label",,,"v2 of create_property_graph_tests.gt") | ("property graph label","{create_property_graph_tests,gt,v2}",{}) + label v2 of vertex v2 of property graph gt | ("property graph element label",,,"v2 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v2}",{}) + label v2 of vertex v2 of property graph gt | ("property graph element label",,,"v2 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v2}",{}) + property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property a of property graph gt | ("property graph property",,,"a of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,a}",{}) + property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property b of property graph gt | ("property graph property",,,"b of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,b}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of property graph gt | ("property graph property",,,"c of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,c}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of property graph gt | ("property graph property",,,"k1 of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,k1}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of property graph gt | ("property graph property",,,"k2 of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,k2}",{}) + property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property m of property graph gt | ("property graph property",,,"m of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,m}",{}) + property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property n of property graph gt | ("property graph property",,,"n of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,n}",{}) + type gt | (type,create_property_graph_tests,gt,create_property_graph_tests.gt) | (type,{create_property_graph_tests.gt},{}) + type gt[] | (type,create_property_graph_tests,_gt,create_property_graph_tests.gt[]) | (type,{create_property_graph_tests.gt[]},{}) + vertex v1 of property graph gt | ("property graph element",,,"v1 of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,v1}",{}) + vertex v2 of property graph gt | ("property graph element",,,"v2 of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,v2}",{}) +(52 rows) + \a\t SELECT pg_get_propgraphdef('g2'::regclass); CREATE PROPERTY GRAPH create_property_graph_tests.g2 diff --git a/src/test/regress/expected/event_trigger.out b/src/test/regress/expected/event_trigger.out index 065f586310f..ed8d5df397e 100644 --- a/src/test/regress/expected/event_trigger.out +++ b/src/test/regress/expected/event_trigger.out @@ -173,6 +173,23 @@ NOTICE: test_event_trigger: ddl_command_end CREATE USER MAPPING alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; NOTICE: test_event_trigger: ddl_command_end ALTER DEFAULT PRIVILEGES +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE TABLE t2x (i int PRIMARY KEY, j text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); +NOTICE: test_event_trigger: ddl_command_end CREATE PROPERTY GRAPH +DROP PROPERTY GRAPH gx; +NOTICE: test_event_trigger: ddl_command_end DROP PROPERTY GRAPH +DROP TABLE t1x, t2x; +NOTICE: test_event_trigger: ddl_command_end DROP TABLE -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; ERROR: permission denied to change owner of event trigger "regress_event_trigger" diff --git a/src/test/regress/expected/object_address.out b/src/test/regress/expected/object_address.out index 97227d67a54..5e53f0b092e 100644 --- a/src/test/regress/expected/object_address.out +++ b/src/test/regress/expected/object_address.out @@ -67,7 +67,9 @@ DECLARE BEGIN FOR objtype IN VALUES ('toast table'), ('index column'), ('sequence column'), ('toast table column'), ('view column'), ('materialized view column'), - ('property graph element'), ('property graph label'), ('property graph property') + ('property graph element'), ('property graph element label'), + ('property graph label'), ('property graph label property'), + ('property graph property') LOOP BEGIN PERFORM pg_get_object_address(objtype, '{one}', '{}'); @@ -84,7 +86,9 @@ WARNING: error for toast table column: unsupported object type "toast table col WARNING: error for view column: unsupported object type "view column" WARNING: error for materialized view column: unsupported object type "materialized view column" WARNING: error for property graph element: unsupported object type "property graph element" +WARNING: error for property graph element label: unrecognized object type "property graph element label" WARNING: error for property graph label: unsupported object type "property graph label" +WARNING: error for property graph label property: unrecognized object type "property graph label property" WARNING: error for property graph property: unsupported object type "property graph property" -- miscellaneous other errors select * from pg_get_object_address('operator of access method', '{btree,integer_ops,1}', '{int4,bool}'); @@ -593,7 +597,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace @@ -653,6 +659,8 @@ ORDER BY objects.classid, objects.objid, objects.objsubid; ("(""parameter ACL"",,,)")|("(""parameter ACL"",,)")|NULL ("(""property graph element"",,,)")|("(""property graph element"",,)")|NULL ("(""property graph label"",,,)")|("(""property graph label"",,)")|NULL +("(""property graph element label"",,,)")|("(""property graph element label"",,)")|NULL ("(""property graph property"",,,)")|("(""property graph property"",,)")|NULL +("(""property graph label property"",,,)")|("(""property graph label property"",,)")|NULL -- restore normal output mode \a\t diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..9608dd5c4af 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -298,6 +298,29 @@ SELECT (pg_identify_object(classid, objid, objsubid)).* refobjid = 'create_property_graph_tests.g2'::regclass ORDER BY 1, 2, 3, 4; +-- test object address functions with recursive dependency walk +-- covers all property graph object types including indirect dependents +SELECT * +FROM ( + WITH RECURSIVE deps (classid, objid, objsubid, refclassid, refobjid, refobjsubid) AS ( + SELECT classid, objid, objsubid, + refclassid, refobjid, refobjsubid + FROM pg_depend + WHERE refclassid = 'pg_class'::regclass AND + refobjid = 'create_property_graph_tests.gt'::regclass + UNION ALL + SELECT d.classid, d.objid, d.objsubid, + d.refclassid, d.refobjid, d.refobjsubid + FROM pg_depend d + JOIN deps dp ON d.refclassid = dp.classid AND d.refobjid = dp.objid AND d.refobjsubid = dp.objsubid + ) + SELECT pg_describe_object(classid, objid, objsubid) as obj, + pg_identify_object(classid, objid, objsubid) as ident, + pg_identify_object_as_address(classid, objid, objsubid) as addr + FROM deps +) s +ORDER BY obj COLLATE "C", ident::text COLLATE "C"; + \a\t SELECT pg_get_propgraphdef('g2'::regclass); SELECT pg_get_propgraphdef('g3'::regclass); diff --git a/src/test/regress/sql/event_trigger.sql b/src/test/regress/sql/event_trigger.sql index 32e9bb58c5e..271f443378b 100644 --- a/src/test/regress/sql/event_trigger.sql +++ b/src/test/regress/sql/event_trigger.sql @@ -143,6 +143,19 @@ create user mapping for regress_evt_user server useless_server; alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +CREATE TABLE t2x (i int PRIMARY KEY, j text); + +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); + +DROP PROPERTY GRAPH gx; +DROP TABLE t1x, t2x; + -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; diff --git a/src/test/regress/sql/object_address.sql b/src/test/regress/sql/object_address.sql index 1bbe9457c1c..27109d421c7 100644 --- a/src/test/regress/sql/object_address.sql +++ b/src/test/regress/sql/object_address.sql @@ -67,7 +67,9 @@ DECLARE BEGIN FOR objtype IN VALUES ('toast table'), ('index column'), ('sequence column'), ('toast table column'), ('view column'), ('materialized view column'), - ('property graph element'), ('property graph label'), ('property graph property') + ('property graph element'), ('property graph element label'), + ('property graph label'), ('property graph label property'), + ('property graph property') LOOP BEGIN PERFORM pg_get_object_address(objtype, '{one}', '{}'); @@ -282,7 +284,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace -- 2.34.1 --R84XrR4Hgw0dH3Ec-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v2] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-23 09:27 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-23 09:27 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing them to hit the default case and error out with "unsupported object class". During DROP PROPERTY GRAPH, this manifests when an event trigger is active, because pg_event_trigger_ddl_commands() calls these functions. The same code paths are also reachable via pg_identify_object() and pg_identify_object_as_address(). This commit adds the missing cases. Test coverage is added in object_address.sql for these two catalog types via the zero-OID test that exercises pg_identify_object() and pg_identify_object_as_address(). A test in event_trigger.sql verifies that DROP PROPERTY GRAPH works correctly when an event trigger is active. Author: Bertrand Drouvot <[email protected]> Reviewed-by: Michael Paquier <[email protected]> Reviewed-by: Ashutosh Bapat <[email protected]> Discussion: https://postgr.es/m/aej1DkLwhyZWmtxJ@bdtpg --- src/backend/catalog/objectaddress.c | 93 ++++++++++++++++++++ src/test/regress/expected/event_trigger.out | 17 ++++ src/test/regress/expected/object_address.out | 4 + src/test/regress/sql/event_trigger.sql | 13 +++ src/test/regress/sql/object_address.sql | 2 + 5 files changed, 129 insertions(+) 62.4% src/backend/catalog/ 25.6% src/test/regress/expected/ 11.8% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/event_trigger.out b/src/test/regress/expected/event_trigger.out index 065f586310f..ed8d5df397e 100644 --- a/src/test/regress/expected/event_trigger.out +++ b/src/test/regress/expected/event_trigger.out @@ -173,6 +173,23 @@ NOTICE: test_event_trigger: ddl_command_end CREATE USER MAPPING alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; NOTICE: test_event_trigger: ddl_command_end ALTER DEFAULT PRIVILEGES +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE TABLE t2x (i int PRIMARY KEY, j text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); +NOTICE: test_event_trigger: ddl_command_end CREATE PROPERTY GRAPH +DROP PROPERTY GRAPH gx; +NOTICE: test_event_trigger: ddl_command_end DROP PROPERTY GRAPH +DROP TABLE t1x, t2x; +NOTICE: test_event_trigger: ddl_command_end DROP TABLE -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; ERROR: permission denied to change owner of event trigger "regress_event_trigger" diff --git a/src/test/regress/expected/object_address.out b/src/test/regress/expected/object_address.out index 97227d67a54..729c3537f25 100644 --- a/src/test/regress/expected/object_address.out +++ b/src/test/regress/expected/object_address.out @@ -593,7 +593,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace @@ -653,6 +655,8 @@ ORDER BY objects.classid, objects.objid, objects.objsubid; ("(""parameter ACL"",,,)")|("(""parameter ACL"",,)")|NULL ("(""property graph element"",,,)")|("(""property graph element"",,)")|NULL ("(""property graph label"",,,)")|("(""property graph label"",,)")|NULL +("(""property graph element label"",,,)")|("(""property graph element label"",,)")|NULL ("(""property graph property"",,,)")|("(""property graph property"",,)")|NULL +("(""property graph label property"",,,)")|("(""property graph label property"",,)")|NULL -- restore normal output mode \a\t diff --git a/src/test/regress/sql/event_trigger.sql b/src/test/regress/sql/event_trigger.sql index 32e9bb58c5e..271f443378b 100644 --- a/src/test/regress/sql/event_trigger.sql +++ b/src/test/regress/sql/event_trigger.sql @@ -143,6 +143,19 @@ create user mapping for regress_evt_user server useless_server; alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +CREATE TABLE t2x (i int PRIMARY KEY, j text); + +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); + +DROP PROPERTY GRAPH gx; +DROP TABLE t1x, t2x; + -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; diff --git a/src/test/regress/sql/object_address.sql b/src/test/regress/sql/object_address.sql index 1bbe9457c1c..620dacf1045 100644 --- a/src/test/regress/sql/object_address.sql +++ b/src/test/regress/sql/object_address.sql @@ -282,7 +282,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace -- 2.34.1 --gtUR827Uq8d5gVsQ-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v2] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-23 09:27 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-23 09:27 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing them to hit the default case and error out with "unsupported object class". During DROP PROPERTY GRAPH, this manifests when an event trigger is active, because pg_event_trigger_ddl_commands() calls these functions. The same code paths are also reachable via pg_identify_object() and pg_identify_object_as_address(). This commit adds the missing cases. Test coverage is added in object_address.sql for these two catalog types via the zero-OID test that exercises pg_identify_object() and pg_identify_object_as_address(). A test in event_trigger.sql verifies that DROP PROPERTY GRAPH works correctly when an event trigger is active. Author: Bertrand Drouvot <[email protected]> Reviewed-by: Michael Paquier <[email protected]> Reviewed-by: Ashutosh Bapat <[email protected]> Discussion: https://postgr.es/m/aej1DkLwhyZWmtxJ@bdtpg --- src/backend/catalog/objectaddress.c | 93 ++++++++++++++++++++ src/test/regress/expected/event_trigger.out | 17 ++++ src/test/regress/expected/object_address.out | 4 + src/test/regress/sql/event_trigger.sql | 13 +++ src/test/regress/sql/object_address.sql | 2 + 5 files changed, 129 insertions(+) 62.4% src/backend/catalog/ 25.6% src/test/regress/expected/ 11.8% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/event_trigger.out b/src/test/regress/expected/event_trigger.out index 065f586310f..ed8d5df397e 100644 --- a/src/test/regress/expected/event_trigger.out +++ b/src/test/regress/expected/event_trigger.out @@ -173,6 +173,23 @@ NOTICE: test_event_trigger: ddl_command_end CREATE USER MAPPING alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; NOTICE: test_event_trigger: ddl_command_end ALTER DEFAULT PRIVILEGES +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE TABLE t2x (i int PRIMARY KEY, j text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); +NOTICE: test_event_trigger: ddl_command_end CREATE PROPERTY GRAPH +DROP PROPERTY GRAPH gx; +NOTICE: test_event_trigger: ddl_command_end DROP PROPERTY GRAPH +DROP TABLE t1x, t2x; +NOTICE: test_event_trigger: ddl_command_end DROP TABLE -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; ERROR: permission denied to change owner of event trigger "regress_event_trigger" diff --git a/src/test/regress/expected/object_address.out b/src/test/regress/expected/object_address.out index 97227d67a54..729c3537f25 100644 --- a/src/test/regress/expected/object_address.out +++ b/src/test/regress/expected/object_address.out @@ -593,7 +593,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace @@ -653,6 +655,8 @@ ORDER BY objects.classid, objects.objid, objects.objsubid; ("(""parameter ACL"",,,)")|("(""parameter ACL"",,)")|NULL ("(""property graph element"",,,)")|("(""property graph element"",,)")|NULL ("(""property graph label"",,,)")|("(""property graph label"",,)")|NULL +("(""property graph element label"",,,)")|("(""property graph element label"",,)")|NULL ("(""property graph property"",,,)")|("(""property graph property"",,)")|NULL +("(""property graph label property"",,,)")|("(""property graph label property"",,)")|NULL -- restore normal output mode \a\t diff --git a/src/test/regress/sql/event_trigger.sql b/src/test/regress/sql/event_trigger.sql index 32e9bb58c5e..271f443378b 100644 --- a/src/test/regress/sql/event_trigger.sql +++ b/src/test/regress/sql/event_trigger.sql @@ -143,6 +143,19 @@ create user mapping for regress_evt_user server useless_server; alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +CREATE TABLE t2x (i int PRIMARY KEY, j text); + +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); + +DROP PROPERTY GRAPH gx; +DROP TABLE t1x, t2x; + -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; diff --git a/src/test/regress/sql/object_address.sql b/src/test/regress/sql/object_address.sql index 1bbe9457c1c..620dacf1045 100644 --- a/src/test/regress/sql/object_address.sql +++ b/src/test/regress/sql/object_address.sql @@ -282,7 +282,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace -- 2.34.1 --gtUR827Uq8d5gVsQ-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v2] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-23 09:27 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-23 09:27 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing them to hit the default case and error out with "unsupported object class". During DROP PROPERTY GRAPH, this manifests when an event trigger is active, because pg_event_trigger_ddl_commands() calls these functions. The same code paths are also reachable via pg_identify_object() and pg_identify_object_as_address(). This commit adds the missing cases. Test coverage is added in object_address.sql for these two catalog types via the zero-OID test that exercises pg_identify_object() and pg_identify_object_as_address(). A test in event_trigger.sql verifies that DROP PROPERTY GRAPH works correctly when an event trigger is active. Author: Bertrand Drouvot <[email protected]> Reviewed-by: Michael Paquier <[email protected]> Reviewed-by: Ashutosh Bapat <[email protected]> Discussion: https://postgr.es/m/aej1DkLwhyZWmtxJ@bdtpg --- src/backend/catalog/objectaddress.c | 93 ++++++++++++++++++++ src/test/regress/expected/event_trigger.out | 17 ++++ src/test/regress/expected/object_address.out | 4 + src/test/regress/sql/event_trigger.sql | 13 +++ src/test/regress/sql/object_address.sql | 2 + 5 files changed, 129 insertions(+) 62.4% src/backend/catalog/ 25.6% src/test/regress/expected/ 11.8% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/event_trigger.out b/src/test/regress/expected/event_trigger.out index 065f586310f..ed8d5df397e 100644 --- a/src/test/regress/expected/event_trigger.out +++ b/src/test/regress/expected/event_trigger.out @@ -173,6 +173,23 @@ NOTICE: test_event_trigger: ddl_command_end CREATE USER MAPPING alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; NOTICE: test_event_trigger: ddl_command_end ALTER DEFAULT PRIVILEGES +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE TABLE t2x (i int PRIMARY KEY, j text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); +NOTICE: test_event_trigger: ddl_command_end CREATE PROPERTY GRAPH +DROP PROPERTY GRAPH gx; +NOTICE: test_event_trigger: ddl_command_end DROP PROPERTY GRAPH +DROP TABLE t1x, t2x; +NOTICE: test_event_trigger: ddl_command_end DROP TABLE -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; ERROR: permission denied to change owner of event trigger "regress_event_trigger" diff --git a/src/test/regress/expected/object_address.out b/src/test/regress/expected/object_address.out index 97227d67a54..729c3537f25 100644 --- a/src/test/regress/expected/object_address.out +++ b/src/test/regress/expected/object_address.out @@ -593,7 +593,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace @@ -653,6 +655,8 @@ ORDER BY objects.classid, objects.objid, objects.objsubid; ("(""parameter ACL"",,,)")|("(""parameter ACL"",,)")|NULL ("(""property graph element"",,,)")|("(""property graph element"",,)")|NULL ("(""property graph label"",,,)")|("(""property graph label"",,)")|NULL +("(""property graph element label"",,,)")|("(""property graph element label"",,)")|NULL ("(""property graph property"",,,)")|("(""property graph property"",,)")|NULL +("(""property graph label property"",,,)")|("(""property graph label property"",,)")|NULL -- restore normal output mode \a\t diff --git a/src/test/regress/sql/event_trigger.sql b/src/test/regress/sql/event_trigger.sql index 32e9bb58c5e..271f443378b 100644 --- a/src/test/regress/sql/event_trigger.sql +++ b/src/test/regress/sql/event_trigger.sql @@ -143,6 +143,19 @@ create user mapping for regress_evt_user server useless_server; alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +CREATE TABLE t2x (i int PRIMARY KEY, j text); + +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); + +DROP PROPERTY GRAPH gx; +DROP TABLE t1x, t2x; + -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; diff --git a/src/test/regress/sql/object_address.sql b/src/test/regress/sql/object_address.sql index 1bbe9457c1c..620dacf1045 100644 --- a/src/test/regress/sql/object_address.sql +++ b/src/test/regress/sql/object_address.sql @@ -282,7 +282,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace -- 2.34.1 --gtUR827Uq8d5gVsQ-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v3] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-23 09:27 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-23 09:27 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing them to hit the default case and error out with "unsupported object class". During DROP PROPERTY GRAPH, this manifests when an event trigger is active, because pg_event_trigger_ddl_commands() calls these functions. The same code paths are also reachable via pg_identify_object() and pg_identify_object_as_address(). This commit adds the missing cases. Test coverage is added in object_address.sql for these two catalog types and in create_property_graph.sql covering all property graph object types. A test in event_trigger.sql verifies that DROP PROPERTY GRAPH works correctly when an event trigger is active. Author: Bertrand Drouvot <[email protected]> Reviewed-by: Michael Paquier <[email protected]> Reviewed-by: Ashutosh Bapat <[email protected]> Discussion: https://postgr.es/m/aej1DkLwhyZWmtxJ@bdtpg --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 78 ++++++++++++++++ src/test/regress/expected/event_trigger.out | 17 ++++ src/test/regress/expected/object_address.out | 10 +- .../regress/sql/create_property_graph.sql | 23 +++++ src/test/regress/sql/event_trigger.sql | 13 +++ src/test/regress/sql/object_address.sql | 6 +- 7 files changed, 238 insertions(+), 2 deletions(-) 14.7% src/backend/catalog/ 75.5% src/test/regress/expected/ 9.7% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..eb9e17fb727 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -752,6 +752,84 @@ SELECT (pg_identify_object(classid, objid, objsubid)).* type | create_property_graph_tests | g2 | create_property_graph_tests.g2 (21 rows) +-- test object address functions with recursive dependency walk +-- covers all property graph object types including indirect dependents +SELECT * +FROM ( + WITH RECURSIVE deps (classid, objid, objsubid, refclassid, refobjid, refobjsubid) AS ( + SELECT classid, objid, objsubid, + refclassid, refobjid, refobjsubid + FROM pg_depend + WHERE refclassid = 'pg_class'::regclass AND + refobjid = 'create_property_graph_tests.gt'::regclass + UNION ALL + SELECT d.classid, d.objid, d.objsubid, + d.refclassid, d.refobjid, d.refobjsubid + FROM pg_depend d + JOIN deps dp ON d.refclassid = dp.classid AND d.refobjid = dp.objid AND d.refobjsubid = dp.objsubid + ) + SELECT pg_describe_object(classid, objid, objsubid) as obj, + pg_identify_object(classid, objid, objsubid) as ident, + pg_identify_object_as_address(classid, objid, objsubid) as addr + FROM deps +) s +ORDER BY obj COLLATE "C", ident::text COLLATE "C"; + obj | ident | addr +----------------------------------------------------------+----------------------------------------------------------------------------+---------------------------------------------------------------------------- + edge e of property graph gt | ("property graph element",,,"e of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,e}",{}) + edge e of property graph gt | ("property graph element",,,"e of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,e}",{}) + edge e of property graph gt | ("property graph element",,,"e of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of property graph gt | ("property graph label",,,"e of create_property_graph_tests.gt") | ("property graph label","{create_property_graph_tests,gt,e}",{}) + label v1 of property graph gt | ("property graph label",,,"v1 of create_property_graph_tests.gt") | ("property graph label","{create_property_graph_tests,gt,v1}",{}) + label v1 of vertex v1 of property graph gt | ("property graph element label",,,"v1 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v1}",{}) + label v1 of vertex v1 of property graph gt | ("property graph element label",,,"v1 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v1}",{}) + label v2 of property graph gt | ("property graph label",,,"v2 of create_property_graph_tests.gt") | ("property graph label","{create_property_graph_tests,gt,v2}",{}) + label v2 of vertex v2 of property graph gt | ("property graph element label",,,"v2 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v2}",{}) + label v2 of vertex v2 of property graph gt | ("property graph element label",,,"v2 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v2}",{}) + property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property a of property graph gt | ("property graph property",,,"a of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,a}",{}) + property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property b of property graph gt | ("property graph property",,,"b of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,b}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of property graph gt | ("property graph property",,,"c of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,c}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of property graph gt | ("property graph property",,,"k1 of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,k1}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of property graph gt | ("property graph property",,,"k2 of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,k2}",{}) + property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property m of property graph gt | ("property graph property",,,"m of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,m}",{}) + property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property n of property graph gt | ("property graph property",,,"n of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,n}",{}) + type gt | (type,create_property_graph_tests,gt,create_property_graph_tests.gt) | (type,{create_property_graph_tests.gt},{}) + type gt[] | (type,create_property_graph_tests,_gt,create_property_graph_tests.gt[]) | (type,{create_property_graph_tests.gt[]},{}) + vertex v1 of property graph gt | ("property graph element",,,"v1 of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,v1}",{}) + vertex v2 of property graph gt | ("property graph element",,,"v2 of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,v2}",{}) +(52 rows) + \a\t SELECT pg_get_propgraphdef('g2'::regclass); CREATE PROPERTY GRAPH create_property_graph_tests.g2 diff --git a/src/test/regress/expected/event_trigger.out b/src/test/regress/expected/event_trigger.out index 065f586310f..ed8d5df397e 100644 --- a/src/test/regress/expected/event_trigger.out +++ b/src/test/regress/expected/event_trigger.out @@ -173,6 +173,23 @@ NOTICE: test_event_trigger: ddl_command_end CREATE USER MAPPING alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; NOTICE: test_event_trigger: ddl_command_end ALTER DEFAULT PRIVILEGES +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE TABLE t2x (i int PRIMARY KEY, j text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); +NOTICE: test_event_trigger: ddl_command_end CREATE PROPERTY GRAPH +DROP PROPERTY GRAPH gx; +NOTICE: test_event_trigger: ddl_command_end DROP PROPERTY GRAPH +DROP TABLE t1x, t2x; +NOTICE: test_event_trigger: ddl_command_end DROP TABLE -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; ERROR: permission denied to change owner of event trigger "regress_event_trigger" diff --git a/src/test/regress/expected/object_address.out b/src/test/regress/expected/object_address.out index 97227d67a54..5e53f0b092e 100644 --- a/src/test/regress/expected/object_address.out +++ b/src/test/regress/expected/object_address.out @@ -67,7 +67,9 @@ DECLARE BEGIN FOR objtype IN VALUES ('toast table'), ('index column'), ('sequence column'), ('toast table column'), ('view column'), ('materialized view column'), - ('property graph element'), ('property graph label'), ('property graph property') + ('property graph element'), ('property graph element label'), + ('property graph label'), ('property graph label property'), + ('property graph property') LOOP BEGIN PERFORM pg_get_object_address(objtype, '{one}', '{}'); @@ -84,7 +86,9 @@ WARNING: error for toast table column: unsupported object type "toast table col WARNING: error for view column: unsupported object type "view column" WARNING: error for materialized view column: unsupported object type "materialized view column" WARNING: error for property graph element: unsupported object type "property graph element" +WARNING: error for property graph element label: unrecognized object type "property graph element label" WARNING: error for property graph label: unsupported object type "property graph label" +WARNING: error for property graph label property: unrecognized object type "property graph label property" WARNING: error for property graph property: unsupported object type "property graph property" -- miscellaneous other errors select * from pg_get_object_address('operator of access method', '{btree,integer_ops,1}', '{int4,bool}'); @@ -593,7 +597,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace @@ -653,6 +659,8 @@ ORDER BY objects.classid, objects.objid, objects.objsubid; ("(""parameter ACL"",,,)")|("(""parameter ACL"",,)")|NULL ("(""property graph element"",,,)")|("(""property graph element"",,)")|NULL ("(""property graph label"",,,)")|("(""property graph label"",,)")|NULL +("(""property graph element label"",,,)")|("(""property graph element label"",,)")|NULL ("(""property graph property"",,,)")|("(""property graph property"",,)")|NULL +("(""property graph label property"",,,)")|("(""property graph label property"",,)")|NULL -- restore normal output mode \a\t diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..9608dd5c4af 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -298,6 +298,29 @@ SELECT (pg_identify_object(classid, objid, objsubid)).* refobjid = 'create_property_graph_tests.g2'::regclass ORDER BY 1, 2, 3, 4; +-- test object address functions with recursive dependency walk +-- covers all property graph object types including indirect dependents +SELECT * +FROM ( + WITH RECURSIVE deps (classid, objid, objsubid, refclassid, refobjid, refobjsubid) AS ( + SELECT classid, objid, objsubid, + refclassid, refobjid, refobjsubid + FROM pg_depend + WHERE refclassid = 'pg_class'::regclass AND + refobjid = 'create_property_graph_tests.gt'::regclass + UNION ALL + SELECT d.classid, d.objid, d.objsubid, + d.refclassid, d.refobjid, d.refobjsubid + FROM pg_depend d + JOIN deps dp ON d.refclassid = dp.classid AND d.refobjid = dp.objid AND d.refobjsubid = dp.objsubid + ) + SELECT pg_describe_object(classid, objid, objsubid) as obj, + pg_identify_object(classid, objid, objsubid) as ident, + pg_identify_object_as_address(classid, objid, objsubid) as addr + FROM deps +) s +ORDER BY obj COLLATE "C", ident::text COLLATE "C"; + \a\t SELECT pg_get_propgraphdef('g2'::regclass); SELECT pg_get_propgraphdef('g3'::regclass); diff --git a/src/test/regress/sql/event_trigger.sql b/src/test/regress/sql/event_trigger.sql index 32e9bb58c5e..271f443378b 100644 --- a/src/test/regress/sql/event_trigger.sql +++ b/src/test/regress/sql/event_trigger.sql @@ -143,6 +143,19 @@ create user mapping for regress_evt_user server useless_server; alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +CREATE TABLE t2x (i int PRIMARY KEY, j text); + +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); + +DROP PROPERTY GRAPH gx; +DROP TABLE t1x, t2x; + -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; diff --git a/src/test/regress/sql/object_address.sql b/src/test/regress/sql/object_address.sql index 1bbe9457c1c..27109d421c7 100644 --- a/src/test/regress/sql/object_address.sql +++ b/src/test/regress/sql/object_address.sql @@ -67,7 +67,9 @@ DECLARE BEGIN FOR objtype IN VALUES ('toast table'), ('index column'), ('sequence column'), ('toast table column'), ('view column'), ('materialized view column'), - ('property graph element'), ('property graph label'), ('property graph property') + ('property graph element'), ('property graph element label'), + ('property graph label'), ('property graph label property'), + ('property graph property') LOOP BEGIN PERFORM pg_get_object_address(objtype, '{one}', '{}'); @@ -282,7 +284,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace -- 2.34.1 --R84XrR4Hgw0dH3Ec-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v3] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-23 09:27 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-23 09:27 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing them to hit the default case and error out with "unsupported object class". During DROP PROPERTY GRAPH, this manifests when an event trigger is active, because pg_event_trigger_ddl_commands() calls these functions. The same code paths are also reachable via pg_identify_object() and pg_identify_object_as_address(). This commit adds the missing cases. Test coverage is added in object_address.sql for these two catalog types and in create_property_graph.sql covering all property graph object types. A test in event_trigger.sql verifies that DROP PROPERTY GRAPH works correctly when an event trigger is active. Author: Bertrand Drouvot <[email protected]> Reviewed-by: Michael Paquier <[email protected]> Reviewed-by: Ashutosh Bapat <[email protected]> Discussion: https://postgr.es/m/aej1DkLwhyZWmtxJ@bdtpg --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 78 ++++++++++++++++ src/test/regress/expected/event_trigger.out | 17 ++++ src/test/regress/expected/object_address.out | 10 +- .../regress/sql/create_property_graph.sql | 23 +++++ src/test/regress/sql/event_trigger.sql | 13 +++ src/test/regress/sql/object_address.sql | 6 +- 7 files changed, 238 insertions(+), 2 deletions(-) 14.7% src/backend/catalog/ 75.5% src/test/regress/expected/ 9.7% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..eb9e17fb727 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -752,6 +752,84 @@ SELECT (pg_identify_object(classid, objid, objsubid)).* type | create_property_graph_tests | g2 | create_property_graph_tests.g2 (21 rows) +-- test object address functions with recursive dependency walk +-- covers all property graph object types including indirect dependents +SELECT * +FROM ( + WITH RECURSIVE deps (classid, objid, objsubid, refclassid, refobjid, refobjsubid) AS ( + SELECT classid, objid, objsubid, + refclassid, refobjid, refobjsubid + FROM pg_depend + WHERE refclassid = 'pg_class'::regclass AND + refobjid = 'create_property_graph_tests.gt'::regclass + UNION ALL + SELECT d.classid, d.objid, d.objsubid, + d.refclassid, d.refobjid, d.refobjsubid + FROM pg_depend d + JOIN deps dp ON d.refclassid = dp.classid AND d.refobjid = dp.objid AND d.refobjsubid = dp.objsubid + ) + SELECT pg_describe_object(classid, objid, objsubid) as obj, + pg_identify_object(classid, objid, objsubid) as ident, + pg_identify_object_as_address(classid, objid, objsubid) as addr + FROM deps +) s +ORDER BY obj COLLATE "C", ident::text COLLATE "C"; + obj | ident | addr +----------------------------------------------------------+----------------------------------------------------------------------------+---------------------------------------------------------------------------- + edge e of property graph gt | ("property graph element",,,"e of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,e}",{}) + edge e of property graph gt | ("property graph element",,,"e of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,e}",{}) + edge e of property graph gt | ("property graph element",,,"e of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of property graph gt | ("property graph label",,,"e of create_property_graph_tests.gt") | ("property graph label","{create_property_graph_tests,gt,e}",{}) + label v1 of property graph gt | ("property graph label",,,"v1 of create_property_graph_tests.gt") | ("property graph label","{create_property_graph_tests,gt,v1}",{}) + label v1 of vertex v1 of property graph gt | ("property graph element label",,,"v1 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v1}",{}) + label v1 of vertex v1 of property graph gt | ("property graph element label",,,"v1 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v1}",{}) + label v2 of property graph gt | ("property graph label",,,"v2 of create_property_graph_tests.gt") | ("property graph label","{create_property_graph_tests,gt,v2}",{}) + label v2 of vertex v2 of property graph gt | ("property graph element label",,,"v2 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v2}",{}) + label v2 of vertex v2 of property graph gt | ("property graph element label",,,"v2 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v2}",{}) + property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property a of property graph gt | ("property graph property",,,"a of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,a}",{}) + property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property b of property graph gt | ("property graph property",,,"b of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,b}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of property graph gt | ("property graph property",,,"c of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,c}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of property graph gt | ("property graph property",,,"k1 of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,k1}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of property graph gt | ("property graph property",,,"k2 of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,k2}",{}) + property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property m of property graph gt | ("property graph property",,,"m of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,m}",{}) + property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property n of property graph gt | ("property graph property",,,"n of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,n}",{}) + type gt | (type,create_property_graph_tests,gt,create_property_graph_tests.gt) | (type,{create_property_graph_tests.gt},{}) + type gt[] | (type,create_property_graph_tests,_gt,create_property_graph_tests.gt[]) | (type,{create_property_graph_tests.gt[]},{}) + vertex v1 of property graph gt | ("property graph element",,,"v1 of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,v1}",{}) + vertex v2 of property graph gt | ("property graph element",,,"v2 of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,v2}",{}) +(52 rows) + \a\t SELECT pg_get_propgraphdef('g2'::regclass); CREATE PROPERTY GRAPH create_property_graph_tests.g2 diff --git a/src/test/regress/expected/event_trigger.out b/src/test/regress/expected/event_trigger.out index 065f586310f..ed8d5df397e 100644 --- a/src/test/regress/expected/event_trigger.out +++ b/src/test/regress/expected/event_trigger.out @@ -173,6 +173,23 @@ NOTICE: test_event_trigger: ddl_command_end CREATE USER MAPPING alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; NOTICE: test_event_trigger: ddl_command_end ALTER DEFAULT PRIVILEGES +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE TABLE t2x (i int PRIMARY KEY, j text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); +NOTICE: test_event_trigger: ddl_command_end CREATE PROPERTY GRAPH +DROP PROPERTY GRAPH gx; +NOTICE: test_event_trigger: ddl_command_end DROP PROPERTY GRAPH +DROP TABLE t1x, t2x; +NOTICE: test_event_trigger: ddl_command_end DROP TABLE -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; ERROR: permission denied to change owner of event trigger "regress_event_trigger" diff --git a/src/test/regress/expected/object_address.out b/src/test/regress/expected/object_address.out index 97227d67a54..5e53f0b092e 100644 --- a/src/test/regress/expected/object_address.out +++ b/src/test/regress/expected/object_address.out @@ -67,7 +67,9 @@ DECLARE BEGIN FOR objtype IN VALUES ('toast table'), ('index column'), ('sequence column'), ('toast table column'), ('view column'), ('materialized view column'), - ('property graph element'), ('property graph label'), ('property graph property') + ('property graph element'), ('property graph element label'), + ('property graph label'), ('property graph label property'), + ('property graph property') LOOP BEGIN PERFORM pg_get_object_address(objtype, '{one}', '{}'); @@ -84,7 +86,9 @@ WARNING: error for toast table column: unsupported object type "toast table col WARNING: error for view column: unsupported object type "view column" WARNING: error for materialized view column: unsupported object type "materialized view column" WARNING: error for property graph element: unsupported object type "property graph element" +WARNING: error for property graph element label: unrecognized object type "property graph element label" WARNING: error for property graph label: unsupported object type "property graph label" +WARNING: error for property graph label property: unrecognized object type "property graph label property" WARNING: error for property graph property: unsupported object type "property graph property" -- miscellaneous other errors select * from pg_get_object_address('operator of access method', '{btree,integer_ops,1}', '{int4,bool}'); @@ -593,7 +597,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace @@ -653,6 +659,8 @@ ORDER BY objects.classid, objects.objid, objects.objsubid; ("(""parameter ACL"",,,)")|("(""parameter ACL"",,)")|NULL ("(""property graph element"",,,)")|("(""property graph element"",,)")|NULL ("(""property graph label"",,,)")|("(""property graph label"",,)")|NULL +("(""property graph element label"",,,)")|("(""property graph element label"",,)")|NULL ("(""property graph property"",,,)")|("(""property graph property"",,)")|NULL +("(""property graph label property"",,,)")|("(""property graph label property"",,)")|NULL -- restore normal output mode \a\t diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..9608dd5c4af 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -298,6 +298,29 @@ SELECT (pg_identify_object(classid, objid, objsubid)).* refobjid = 'create_property_graph_tests.g2'::regclass ORDER BY 1, 2, 3, 4; +-- test object address functions with recursive dependency walk +-- covers all property graph object types including indirect dependents +SELECT * +FROM ( + WITH RECURSIVE deps (classid, objid, objsubid, refclassid, refobjid, refobjsubid) AS ( + SELECT classid, objid, objsubid, + refclassid, refobjid, refobjsubid + FROM pg_depend + WHERE refclassid = 'pg_class'::regclass AND + refobjid = 'create_property_graph_tests.gt'::regclass + UNION ALL + SELECT d.classid, d.objid, d.objsubid, + d.refclassid, d.refobjid, d.refobjsubid + FROM pg_depend d + JOIN deps dp ON d.refclassid = dp.classid AND d.refobjid = dp.objid AND d.refobjsubid = dp.objsubid + ) + SELECT pg_describe_object(classid, objid, objsubid) as obj, + pg_identify_object(classid, objid, objsubid) as ident, + pg_identify_object_as_address(classid, objid, objsubid) as addr + FROM deps +) s +ORDER BY obj COLLATE "C", ident::text COLLATE "C"; + \a\t SELECT pg_get_propgraphdef('g2'::regclass); SELECT pg_get_propgraphdef('g3'::regclass); diff --git a/src/test/regress/sql/event_trigger.sql b/src/test/regress/sql/event_trigger.sql index 32e9bb58c5e..271f443378b 100644 --- a/src/test/regress/sql/event_trigger.sql +++ b/src/test/regress/sql/event_trigger.sql @@ -143,6 +143,19 @@ create user mapping for regress_evt_user server useless_server; alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +CREATE TABLE t2x (i int PRIMARY KEY, j text); + +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); + +DROP PROPERTY GRAPH gx; +DROP TABLE t1x, t2x; + -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; diff --git a/src/test/regress/sql/object_address.sql b/src/test/regress/sql/object_address.sql index 1bbe9457c1c..27109d421c7 100644 --- a/src/test/regress/sql/object_address.sql +++ b/src/test/regress/sql/object_address.sql @@ -67,7 +67,9 @@ DECLARE BEGIN FOR objtype IN VALUES ('toast table'), ('index column'), ('sequence column'), ('toast table column'), ('view column'), ('materialized view column'), - ('property graph element'), ('property graph label'), ('property graph property') + ('property graph element'), ('property graph element label'), + ('property graph label'), ('property graph label property'), + ('property graph property') LOOP BEGIN PERFORM pg_get_object_address(objtype, '{one}', '{}'); @@ -282,7 +284,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace -- 2.34.1 --R84XrR4Hgw0dH3Ec-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v3] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-23 09:27 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-23 09:27 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing them to hit the default case and error out with "unsupported object class". During DROP PROPERTY GRAPH, this manifests when an event trigger is active, because pg_event_trigger_ddl_commands() calls these functions. The same code paths are also reachable via pg_identify_object() and pg_identify_object_as_address(). This commit adds the missing cases. Test coverage is added in object_address.sql for these two catalog types and in create_property_graph.sql covering all property graph object types. A test in event_trigger.sql verifies that DROP PROPERTY GRAPH works correctly when an event trigger is active. Author: Bertrand Drouvot <[email protected]> Reviewed-by: Michael Paquier <[email protected]> Reviewed-by: Ashutosh Bapat <[email protected]> Discussion: https://postgr.es/m/aej1DkLwhyZWmtxJ@bdtpg --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 78 ++++++++++++++++ src/test/regress/expected/event_trigger.out | 17 ++++ src/test/regress/expected/object_address.out | 10 +- .../regress/sql/create_property_graph.sql | 23 +++++ src/test/regress/sql/event_trigger.sql | 13 +++ src/test/regress/sql/object_address.sql | 6 +- 7 files changed, 238 insertions(+), 2 deletions(-) 14.7% src/backend/catalog/ 75.5% src/test/regress/expected/ 9.7% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..eb9e17fb727 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -752,6 +752,84 @@ SELECT (pg_identify_object(classid, objid, objsubid)).* type | create_property_graph_tests | g2 | create_property_graph_tests.g2 (21 rows) +-- test object address functions with recursive dependency walk +-- covers all property graph object types including indirect dependents +SELECT * +FROM ( + WITH RECURSIVE deps (classid, objid, objsubid, refclassid, refobjid, refobjsubid) AS ( + SELECT classid, objid, objsubid, + refclassid, refobjid, refobjsubid + FROM pg_depend + WHERE refclassid = 'pg_class'::regclass AND + refobjid = 'create_property_graph_tests.gt'::regclass + UNION ALL + SELECT d.classid, d.objid, d.objsubid, + d.refclassid, d.refobjid, d.refobjsubid + FROM pg_depend d + JOIN deps dp ON d.refclassid = dp.classid AND d.refobjid = dp.objid AND d.refobjsubid = dp.objsubid + ) + SELECT pg_describe_object(classid, objid, objsubid) as obj, + pg_identify_object(classid, objid, objsubid) as ident, + pg_identify_object_as_address(classid, objid, objsubid) as addr + FROM deps +) s +ORDER BY obj COLLATE "C", ident::text COLLATE "C"; + obj | ident | addr +----------------------------------------------------------+----------------------------------------------------------------------------+---------------------------------------------------------------------------- + edge e of property graph gt | ("property graph element",,,"e of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,e}",{}) + edge e of property graph gt | ("property graph element",,,"e of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,e}",{}) + edge e of property graph gt | ("property graph element",,,"e of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of property graph gt | ("property graph label",,,"e of create_property_graph_tests.gt") | ("property graph label","{create_property_graph_tests,gt,e}",{}) + label v1 of property graph gt | ("property graph label",,,"v1 of create_property_graph_tests.gt") | ("property graph label","{create_property_graph_tests,gt,v1}",{}) + label v1 of vertex v1 of property graph gt | ("property graph element label",,,"v1 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v1}",{}) + label v1 of vertex v1 of property graph gt | ("property graph element label",,,"v1 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v1}",{}) + label v2 of property graph gt | ("property graph label",,,"v2 of create_property_graph_tests.gt") | ("property graph label","{create_property_graph_tests,gt,v2}",{}) + label v2 of vertex v2 of property graph gt | ("property graph element label",,,"v2 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v2}",{}) + label v2 of vertex v2 of property graph gt | ("property graph element label",,,"v2 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v2}",{}) + property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property a of property graph gt | ("property graph property",,,"a of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,a}",{}) + property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property b of property graph gt | ("property graph property",,,"b of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,b}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of property graph gt | ("property graph property",,,"c of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,c}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of property graph gt | ("property graph property",,,"k1 of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,k1}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of property graph gt | ("property graph property",,,"k2 of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,k2}",{}) + property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property m of property graph gt | ("property graph property",,,"m of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,m}",{}) + property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property n of property graph gt | ("property graph property",,,"n of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,n}",{}) + type gt | (type,create_property_graph_tests,gt,create_property_graph_tests.gt) | (type,{create_property_graph_tests.gt},{}) + type gt[] | (type,create_property_graph_tests,_gt,create_property_graph_tests.gt[]) | (type,{create_property_graph_tests.gt[]},{}) + vertex v1 of property graph gt | ("property graph element",,,"v1 of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,v1}",{}) + vertex v2 of property graph gt | ("property graph element",,,"v2 of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,v2}",{}) +(52 rows) + \a\t SELECT pg_get_propgraphdef('g2'::regclass); CREATE PROPERTY GRAPH create_property_graph_tests.g2 diff --git a/src/test/regress/expected/event_trigger.out b/src/test/regress/expected/event_trigger.out index 065f586310f..ed8d5df397e 100644 --- a/src/test/regress/expected/event_trigger.out +++ b/src/test/regress/expected/event_trigger.out @@ -173,6 +173,23 @@ NOTICE: test_event_trigger: ddl_command_end CREATE USER MAPPING alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; NOTICE: test_event_trigger: ddl_command_end ALTER DEFAULT PRIVILEGES +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE TABLE t2x (i int PRIMARY KEY, j text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); +NOTICE: test_event_trigger: ddl_command_end CREATE PROPERTY GRAPH +DROP PROPERTY GRAPH gx; +NOTICE: test_event_trigger: ddl_command_end DROP PROPERTY GRAPH +DROP TABLE t1x, t2x; +NOTICE: test_event_trigger: ddl_command_end DROP TABLE -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; ERROR: permission denied to change owner of event trigger "regress_event_trigger" diff --git a/src/test/regress/expected/object_address.out b/src/test/regress/expected/object_address.out index 97227d67a54..5e53f0b092e 100644 --- a/src/test/regress/expected/object_address.out +++ b/src/test/regress/expected/object_address.out @@ -67,7 +67,9 @@ DECLARE BEGIN FOR objtype IN VALUES ('toast table'), ('index column'), ('sequence column'), ('toast table column'), ('view column'), ('materialized view column'), - ('property graph element'), ('property graph label'), ('property graph property') + ('property graph element'), ('property graph element label'), + ('property graph label'), ('property graph label property'), + ('property graph property') LOOP BEGIN PERFORM pg_get_object_address(objtype, '{one}', '{}'); @@ -84,7 +86,9 @@ WARNING: error for toast table column: unsupported object type "toast table col WARNING: error for view column: unsupported object type "view column" WARNING: error for materialized view column: unsupported object type "materialized view column" WARNING: error for property graph element: unsupported object type "property graph element" +WARNING: error for property graph element label: unrecognized object type "property graph element label" WARNING: error for property graph label: unsupported object type "property graph label" +WARNING: error for property graph label property: unrecognized object type "property graph label property" WARNING: error for property graph property: unsupported object type "property graph property" -- miscellaneous other errors select * from pg_get_object_address('operator of access method', '{btree,integer_ops,1}', '{int4,bool}'); @@ -593,7 +597,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace @@ -653,6 +659,8 @@ ORDER BY objects.classid, objects.objid, objects.objsubid; ("(""parameter ACL"",,,)")|("(""parameter ACL"",,)")|NULL ("(""property graph element"",,,)")|("(""property graph element"",,)")|NULL ("(""property graph label"",,,)")|("(""property graph label"",,)")|NULL +("(""property graph element label"",,,)")|("(""property graph element label"",,)")|NULL ("(""property graph property"",,,)")|("(""property graph property"",,)")|NULL +("(""property graph label property"",,,)")|("(""property graph label property"",,)")|NULL -- restore normal output mode \a\t diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..9608dd5c4af 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -298,6 +298,29 @@ SELECT (pg_identify_object(classid, objid, objsubid)).* refobjid = 'create_property_graph_tests.g2'::regclass ORDER BY 1, 2, 3, 4; +-- test object address functions with recursive dependency walk +-- covers all property graph object types including indirect dependents +SELECT * +FROM ( + WITH RECURSIVE deps (classid, objid, objsubid, refclassid, refobjid, refobjsubid) AS ( + SELECT classid, objid, objsubid, + refclassid, refobjid, refobjsubid + FROM pg_depend + WHERE refclassid = 'pg_class'::regclass AND + refobjid = 'create_property_graph_tests.gt'::regclass + UNION ALL + SELECT d.classid, d.objid, d.objsubid, + d.refclassid, d.refobjid, d.refobjsubid + FROM pg_depend d + JOIN deps dp ON d.refclassid = dp.classid AND d.refobjid = dp.objid AND d.refobjsubid = dp.objsubid + ) + SELECT pg_describe_object(classid, objid, objsubid) as obj, + pg_identify_object(classid, objid, objsubid) as ident, + pg_identify_object_as_address(classid, objid, objsubid) as addr + FROM deps +) s +ORDER BY obj COLLATE "C", ident::text COLLATE "C"; + \a\t SELECT pg_get_propgraphdef('g2'::regclass); SELECT pg_get_propgraphdef('g3'::regclass); diff --git a/src/test/regress/sql/event_trigger.sql b/src/test/regress/sql/event_trigger.sql index 32e9bb58c5e..271f443378b 100644 --- a/src/test/regress/sql/event_trigger.sql +++ b/src/test/regress/sql/event_trigger.sql @@ -143,6 +143,19 @@ create user mapping for regress_evt_user server useless_server; alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +CREATE TABLE t2x (i int PRIMARY KEY, j text); + +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); + +DROP PROPERTY GRAPH gx; +DROP TABLE t1x, t2x; + -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; diff --git a/src/test/regress/sql/object_address.sql b/src/test/regress/sql/object_address.sql index 1bbe9457c1c..27109d421c7 100644 --- a/src/test/regress/sql/object_address.sql +++ b/src/test/regress/sql/object_address.sql @@ -67,7 +67,9 @@ DECLARE BEGIN FOR objtype IN VALUES ('toast table'), ('index column'), ('sequence column'), ('toast table column'), ('view column'), ('materialized view column'), - ('property graph element'), ('property graph label'), ('property graph property') + ('property graph element'), ('property graph element label'), + ('property graph label'), ('property graph label property'), + ('property graph property') LOOP BEGIN PERFORM pg_get_object_address(objtype, '{one}', '{}'); @@ -282,7 +284,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace -- 2.34.1 --R84XrR4Hgw0dH3Ec-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v3] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-23 09:27 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-23 09:27 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing them to hit the default case and error out with "unsupported object class". During DROP PROPERTY GRAPH, this manifests when an event trigger is active, because pg_event_trigger_ddl_commands() calls these functions. The same code paths are also reachable via pg_identify_object() and pg_identify_object_as_address(). This commit adds the missing cases. Test coverage is added in object_address.sql for these two catalog types and in create_property_graph.sql covering all property graph object types. A test in event_trigger.sql verifies that DROP PROPERTY GRAPH works correctly when an event trigger is active. Author: Bertrand Drouvot <[email protected]> Reviewed-by: Michael Paquier <[email protected]> Reviewed-by: Ashutosh Bapat <[email protected]> Discussion: https://postgr.es/m/aej1DkLwhyZWmtxJ@bdtpg --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 78 ++++++++++++++++ src/test/regress/expected/event_trigger.out | 17 ++++ src/test/regress/expected/object_address.out | 10 +- .../regress/sql/create_property_graph.sql | 23 +++++ src/test/regress/sql/event_trigger.sql | 13 +++ src/test/regress/sql/object_address.sql | 6 +- 7 files changed, 238 insertions(+), 2 deletions(-) 14.7% src/backend/catalog/ 75.5% src/test/regress/expected/ 9.7% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..eb9e17fb727 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -752,6 +752,84 @@ SELECT (pg_identify_object(classid, objid, objsubid)).* type | create_property_graph_tests | g2 | create_property_graph_tests.g2 (21 rows) +-- test object address functions with recursive dependency walk +-- covers all property graph object types including indirect dependents +SELECT * +FROM ( + WITH RECURSIVE deps (classid, objid, objsubid, refclassid, refobjid, refobjsubid) AS ( + SELECT classid, objid, objsubid, + refclassid, refobjid, refobjsubid + FROM pg_depend + WHERE refclassid = 'pg_class'::regclass AND + refobjid = 'create_property_graph_tests.gt'::regclass + UNION ALL + SELECT d.classid, d.objid, d.objsubid, + d.refclassid, d.refobjid, d.refobjsubid + FROM pg_depend d + JOIN deps dp ON d.refclassid = dp.classid AND d.refobjid = dp.objid AND d.refobjsubid = dp.objsubid + ) + SELECT pg_describe_object(classid, objid, objsubid) as obj, + pg_identify_object(classid, objid, objsubid) as ident, + pg_identify_object_as_address(classid, objid, objsubid) as addr + FROM deps +) s +ORDER BY obj COLLATE "C", ident::text COLLATE "C"; + obj | ident | addr +----------------------------------------------------------+----------------------------------------------------------------------------+---------------------------------------------------------------------------- + edge e of property graph gt | ("property graph element",,,"e of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,e}",{}) + edge e of property graph gt | ("property graph element",,,"e of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,e}",{}) + edge e of property graph gt | ("property graph element",,,"e of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of property graph gt | ("property graph label",,,"e of create_property_graph_tests.gt") | ("property graph label","{create_property_graph_tests,gt,e}",{}) + label v1 of property graph gt | ("property graph label",,,"v1 of create_property_graph_tests.gt") | ("property graph label","{create_property_graph_tests,gt,v1}",{}) + label v1 of vertex v1 of property graph gt | ("property graph element label",,,"v1 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v1}",{}) + label v1 of vertex v1 of property graph gt | ("property graph element label",,,"v1 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v1}",{}) + label v2 of property graph gt | ("property graph label",,,"v2 of create_property_graph_tests.gt") | ("property graph label","{create_property_graph_tests,gt,v2}",{}) + label v2 of vertex v2 of property graph gt | ("property graph element label",,,"v2 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v2}",{}) + label v2 of vertex v2 of property graph gt | ("property graph element label",,,"v2 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v2}",{}) + property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property a of property graph gt | ("property graph property",,,"a of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,a}",{}) + property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property b of property graph gt | ("property graph property",,,"b of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,b}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of property graph gt | ("property graph property",,,"c of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,c}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of property graph gt | ("property graph property",,,"k1 of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,k1}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of property graph gt | ("property graph property",,,"k2 of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,k2}",{}) + property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property m of property graph gt | ("property graph property",,,"m of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,m}",{}) + property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property n of property graph gt | ("property graph property",,,"n of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,n}",{}) + type gt | (type,create_property_graph_tests,gt,create_property_graph_tests.gt) | (type,{create_property_graph_tests.gt},{}) + type gt[] | (type,create_property_graph_tests,_gt,create_property_graph_tests.gt[]) | (type,{create_property_graph_tests.gt[]},{}) + vertex v1 of property graph gt | ("property graph element",,,"v1 of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,v1}",{}) + vertex v2 of property graph gt | ("property graph element",,,"v2 of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,v2}",{}) +(52 rows) + \a\t SELECT pg_get_propgraphdef('g2'::regclass); CREATE PROPERTY GRAPH create_property_graph_tests.g2 diff --git a/src/test/regress/expected/event_trigger.out b/src/test/regress/expected/event_trigger.out index 065f586310f..ed8d5df397e 100644 --- a/src/test/regress/expected/event_trigger.out +++ b/src/test/regress/expected/event_trigger.out @@ -173,6 +173,23 @@ NOTICE: test_event_trigger: ddl_command_end CREATE USER MAPPING alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; NOTICE: test_event_trigger: ddl_command_end ALTER DEFAULT PRIVILEGES +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE TABLE t2x (i int PRIMARY KEY, j text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); +NOTICE: test_event_trigger: ddl_command_end CREATE PROPERTY GRAPH +DROP PROPERTY GRAPH gx; +NOTICE: test_event_trigger: ddl_command_end DROP PROPERTY GRAPH +DROP TABLE t1x, t2x; +NOTICE: test_event_trigger: ddl_command_end DROP TABLE -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; ERROR: permission denied to change owner of event trigger "regress_event_trigger" diff --git a/src/test/regress/expected/object_address.out b/src/test/regress/expected/object_address.out index 97227d67a54..5e53f0b092e 100644 --- a/src/test/regress/expected/object_address.out +++ b/src/test/regress/expected/object_address.out @@ -67,7 +67,9 @@ DECLARE BEGIN FOR objtype IN VALUES ('toast table'), ('index column'), ('sequence column'), ('toast table column'), ('view column'), ('materialized view column'), - ('property graph element'), ('property graph label'), ('property graph property') + ('property graph element'), ('property graph element label'), + ('property graph label'), ('property graph label property'), + ('property graph property') LOOP BEGIN PERFORM pg_get_object_address(objtype, '{one}', '{}'); @@ -84,7 +86,9 @@ WARNING: error for toast table column: unsupported object type "toast table col WARNING: error for view column: unsupported object type "view column" WARNING: error for materialized view column: unsupported object type "materialized view column" WARNING: error for property graph element: unsupported object type "property graph element" +WARNING: error for property graph element label: unrecognized object type "property graph element label" WARNING: error for property graph label: unsupported object type "property graph label" +WARNING: error for property graph label property: unrecognized object type "property graph label property" WARNING: error for property graph property: unsupported object type "property graph property" -- miscellaneous other errors select * from pg_get_object_address('operator of access method', '{btree,integer_ops,1}', '{int4,bool}'); @@ -593,7 +597,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace @@ -653,6 +659,8 @@ ORDER BY objects.classid, objects.objid, objects.objsubid; ("(""parameter ACL"",,,)")|("(""parameter ACL"",,)")|NULL ("(""property graph element"",,,)")|("(""property graph element"",,)")|NULL ("(""property graph label"",,,)")|("(""property graph label"",,)")|NULL +("(""property graph element label"",,,)")|("(""property graph element label"",,)")|NULL ("(""property graph property"",,,)")|("(""property graph property"",,)")|NULL +("(""property graph label property"",,,)")|("(""property graph label property"",,)")|NULL -- restore normal output mode \a\t diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..9608dd5c4af 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -298,6 +298,29 @@ SELECT (pg_identify_object(classid, objid, objsubid)).* refobjid = 'create_property_graph_tests.g2'::regclass ORDER BY 1, 2, 3, 4; +-- test object address functions with recursive dependency walk +-- covers all property graph object types including indirect dependents +SELECT * +FROM ( + WITH RECURSIVE deps (classid, objid, objsubid, refclassid, refobjid, refobjsubid) AS ( + SELECT classid, objid, objsubid, + refclassid, refobjid, refobjsubid + FROM pg_depend + WHERE refclassid = 'pg_class'::regclass AND + refobjid = 'create_property_graph_tests.gt'::regclass + UNION ALL + SELECT d.classid, d.objid, d.objsubid, + d.refclassid, d.refobjid, d.refobjsubid + FROM pg_depend d + JOIN deps dp ON d.refclassid = dp.classid AND d.refobjid = dp.objid AND d.refobjsubid = dp.objsubid + ) + SELECT pg_describe_object(classid, objid, objsubid) as obj, + pg_identify_object(classid, objid, objsubid) as ident, + pg_identify_object_as_address(classid, objid, objsubid) as addr + FROM deps +) s +ORDER BY obj COLLATE "C", ident::text COLLATE "C"; + \a\t SELECT pg_get_propgraphdef('g2'::regclass); SELECT pg_get_propgraphdef('g3'::regclass); diff --git a/src/test/regress/sql/event_trigger.sql b/src/test/regress/sql/event_trigger.sql index 32e9bb58c5e..271f443378b 100644 --- a/src/test/regress/sql/event_trigger.sql +++ b/src/test/regress/sql/event_trigger.sql @@ -143,6 +143,19 @@ create user mapping for regress_evt_user server useless_server; alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +CREATE TABLE t2x (i int PRIMARY KEY, j text); + +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); + +DROP PROPERTY GRAPH gx; +DROP TABLE t1x, t2x; + -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; diff --git a/src/test/regress/sql/object_address.sql b/src/test/regress/sql/object_address.sql index 1bbe9457c1c..27109d421c7 100644 --- a/src/test/regress/sql/object_address.sql +++ b/src/test/regress/sql/object_address.sql @@ -67,7 +67,9 @@ DECLARE BEGIN FOR objtype IN VALUES ('toast table'), ('index column'), ('sequence column'), ('toast table column'), ('view column'), ('materialized view column'), - ('property graph element'), ('property graph label'), ('property graph property') + ('property graph element'), ('property graph element label'), + ('property graph label'), ('property graph label property'), + ('property graph property') LOOP BEGIN PERFORM pg_get_object_address(objtype, '{one}', '{}'); @@ -282,7 +284,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace -- 2.34.1 --R84XrR4Hgw0dH3Ec-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v2] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-23 09:27 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-23 09:27 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing them to hit the default case and error out with "unsupported object class". During DROP PROPERTY GRAPH, this manifests when an event trigger is active, because pg_event_trigger_ddl_commands() calls these functions. The same code paths are also reachable via pg_identify_object() and pg_identify_object_as_address(). This commit adds the missing cases. Test coverage is added in object_address.sql for these two catalog types via the zero-OID test that exercises pg_identify_object() and pg_identify_object_as_address(). A test in event_trigger.sql verifies that DROP PROPERTY GRAPH works correctly when an event trigger is active. Author: Bertrand Drouvot <[email protected]> Reviewed-by: Michael Paquier <[email protected]> Reviewed-by: Ashutosh Bapat <[email protected]> Discussion: https://postgr.es/m/aej1DkLwhyZWmtxJ@bdtpg --- src/backend/catalog/objectaddress.c | 93 ++++++++++++++++++++ src/test/regress/expected/event_trigger.out | 17 ++++ src/test/regress/expected/object_address.out | 4 + src/test/regress/sql/event_trigger.sql | 13 +++ src/test/regress/sql/object_address.sql | 2 + 5 files changed, 129 insertions(+) 62.4% src/backend/catalog/ 25.6% src/test/regress/expected/ 11.8% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/event_trigger.out b/src/test/regress/expected/event_trigger.out index 065f586310f..ed8d5df397e 100644 --- a/src/test/regress/expected/event_trigger.out +++ b/src/test/regress/expected/event_trigger.out @@ -173,6 +173,23 @@ NOTICE: test_event_trigger: ddl_command_end CREATE USER MAPPING alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; NOTICE: test_event_trigger: ddl_command_end ALTER DEFAULT PRIVILEGES +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE TABLE t2x (i int PRIMARY KEY, j text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); +NOTICE: test_event_trigger: ddl_command_end CREATE PROPERTY GRAPH +DROP PROPERTY GRAPH gx; +NOTICE: test_event_trigger: ddl_command_end DROP PROPERTY GRAPH +DROP TABLE t1x, t2x; +NOTICE: test_event_trigger: ddl_command_end DROP TABLE -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; ERROR: permission denied to change owner of event trigger "regress_event_trigger" diff --git a/src/test/regress/expected/object_address.out b/src/test/regress/expected/object_address.out index 97227d67a54..729c3537f25 100644 --- a/src/test/regress/expected/object_address.out +++ b/src/test/regress/expected/object_address.out @@ -593,7 +593,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace @@ -653,6 +655,8 @@ ORDER BY objects.classid, objects.objid, objects.objsubid; ("(""parameter ACL"",,,)")|("(""parameter ACL"",,)")|NULL ("(""property graph element"",,,)")|("(""property graph element"",,)")|NULL ("(""property graph label"",,,)")|("(""property graph label"",,)")|NULL +("(""property graph element label"",,,)")|("(""property graph element label"",,)")|NULL ("(""property graph property"",,,)")|("(""property graph property"",,)")|NULL +("(""property graph label property"",,,)")|("(""property graph label property"",,)")|NULL -- restore normal output mode \a\t diff --git a/src/test/regress/sql/event_trigger.sql b/src/test/regress/sql/event_trigger.sql index 32e9bb58c5e..271f443378b 100644 --- a/src/test/regress/sql/event_trigger.sql +++ b/src/test/regress/sql/event_trigger.sql @@ -143,6 +143,19 @@ create user mapping for regress_evt_user server useless_server; alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +CREATE TABLE t2x (i int PRIMARY KEY, j text); + +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); + +DROP PROPERTY GRAPH gx; +DROP TABLE t1x, t2x; + -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; diff --git a/src/test/regress/sql/object_address.sql b/src/test/regress/sql/object_address.sql index 1bbe9457c1c..620dacf1045 100644 --- a/src/test/regress/sql/object_address.sql +++ b/src/test/regress/sql/object_address.sql @@ -282,7 +282,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace -- 2.34.1 --gtUR827Uq8d5gVsQ-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v2] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-23 09:27 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-23 09:27 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing them to hit the default case and error out with "unsupported object class". During DROP PROPERTY GRAPH, this manifests when an event trigger is active, because pg_event_trigger_ddl_commands() calls these functions. The same code paths are also reachable via pg_identify_object() and pg_identify_object_as_address(). This commit adds the missing cases. Test coverage is added in object_address.sql for these two catalog types via the zero-OID test that exercises pg_identify_object() and pg_identify_object_as_address(). A test in event_trigger.sql verifies that DROP PROPERTY GRAPH works correctly when an event trigger is active. Author: Bertrand Drouvot <[email protected]> Reviewed-by: Michael Paquier <[email protected]> Reviewed-by: Ashutosh Bapat <[email protected]> Discussion: https://postgr.es/m/aej1DkLwhyZWmtxJ@bdtpg --- src/backend/catalog/objectaddress.c | 93 ++++++++++++++++++++ src/test/regress/expected/event_trigger.out | 17 ++++ src/test/regress/expected/object_address.out | 4 + src/test/regress/sql/event_trigger.sql | 13 +++ src/test/regress/sql/object_address.sql | 2 + 5 files changed, 129 insertions(+) 62.4% src/backend/catalog/ 25.6% src/test/regress/expected/ 11.8% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/event_trigger.out b/src/test/regress/expected/event_trigger.out index 065f586310f..ed8d5df397e 100644 --- a/src/test/regress/expected/event_trigger.out +++ b/src/test/regress/expected/event_trigger.out @@ -173,6 +173,23 @@ NOTICE: test_event_trigger: ddl_command_end CREATE USER MAPPING alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; NOTICE: test_event_trigger: ddl_command_end ALTER DEFAULT PRIVILEGES +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE TABLE t2x (i int PRIMARY KEY, j text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); +NOTICE: test_event_trigger: ddl_command_end CREATE PROPERTY GRAPH +DROP PROPERTY GRAPH gx; +NOTICE: test_event_trigger: ddl_command_end DROP PROPERTY GRAPH +DROP TABLE t1x, t2x; +NOTICE: test_event_trigger: ddl_command_end DROP TABLE -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; ERROR: permission denied to change owner of event trigger "regress_event_trigger" diff --git a/src/test/regress/expected/object_address.out b/src/test/regress/expected/object_address.out index 97227d67a54..729c3537f25 100644 --- a/src/test/regress/expected/object_address.out +++ b/src/test/regress/expected/object_address.out @@ -593,7 +593,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace @@ -653,6 +655,8 @@ ORDER BY objects.classid, objects.objid, objects.objsubid; ("(""parameter ACL"",,,)")|("(""parameter ACL"",,)")|NULL ("(""property graph element"",,,)")|("(""property graph element"",,)")|NULL ("(""property graph label"",,,)")|("(""property graph label"",,)")|NULL +("(""property graph element label"",,,)")|("(""property graph element label"",,)")|NULL ("(""property graph property"",,,)")|("(""property graph property"",,)")|NULL +("(""property graph label property"",,,)")|("(""property graph label property"",,)")|NULL -- restore normal output mode \a\t diff --git a/src/test/regress/sql/event_trigger.sql b/src/test/regress/sql/event_trigger.sql index 32e9bb58c5e..271f443378b 100644 --- a/src/test/regress/sql/event_trigger.sql +++ b/src/test/regress/sql/event_trigger.sql @@ -143,6 +143,19 @@ create user mapping for regress_evt_user server useless_server; alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +CREATE TABLE t2x (i int PRIMARY KEY, j text); + +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); + +DROP PROPERTY GRAPH gx; +DROP TABLE t1x, t2x; + -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; diff --git a/src/test/regress/sql/object_address.sql b/src/test/regress/sql/object_address.sql index 1bbe9457c1c..620dacf1045 100644 --- a/src/test/regress/sql/object_address.sql +++ b/src/test/regress/sql/object_address.sql @@ -282,7 +282,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace -- 2.34.1 --gtUR827Uq8d5gVsQ-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v3] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-23 09:27 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-23 09:27 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing them to hit the default case and error out with "unsupported object class". During DROP PROPERTY GRAPH, this manifests when an event trigger is active, because pg_event_trigger_ddl_commands() calls these functions. The same code paths are also reachable via pg_identify_object() and pg_identify_object_as_address(). This commit adds the missing cases. Test coverage is added in object_address.sql for these two catalog types and in create_property_graph.sql covering all property graph object types. A test in event_trigger.sql verifies that DROP PROPERTY GRAPH works correctly when an event trigger is active. Author: Bertrand Drouvot <[email protected]> Reviewed-by: Michael Paquier <[email protected]> Reviewed-by: Ashutosh Bapat <[email protected]> Discussion: https://postgr.es/m/aej1DkLwhyZWmtxJ@bdtpg --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 78 ++++++++++++++++ src/test/regress/expected/event_trigger.out | 17 ++++ src/test/regress/expected/object_address.out | 10 +- .../regress/sql/create_property_graph.sql | 23 +++++ src/test/regress/sql/event_trigger.sql | 13 +++ src/test/regress/sql/object_address.sql | 6 +- 7 files changed, 238 insertions(+), 2 deletions(-) 14.7% src/backend/catalog/ 75.5% src/test/regress/expected/ 9.7% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..eb9e17fb727 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -752,6 +752,84 @@ SELECT (pg_identify_object(classid, objid, objsubid)).* type | create_property_graph_tests | g2 | create_property_graph_tests.g2 (21 rows) +-- test object address functions with recursive dependency walk +-- covers all property graph object types including indirect dependents +SELECT * +FROM ( + WITH RECURSIVE deps (classid, objid, objsubid, refclassid, refobjid, refobjsubid) AS ( + SELECT classid, objid, objsubid, + refclassid, refobjid, refobjsubid + FROM pg_depend + WHERE refclassid = 'pg_class'::regclass AND + refobjid = 'create_property_graph_tests.gt'::regclass + UNION ALL + SELECT d.classid, d.objid, d.objsubid, + d.refclassid, d.refobjid, d.refobjsubid + FROM pg_depend d + JOIN deps dp ON d.refclassid = dp.classid AND d.refobjid = dp.objid AND d.refobjsubid = dp.objsubid + ) + SELECT pg_describe_object(classid, objid, objsubid) as obj, + pg_identify_object(classid, objid, objsubid) as ident, + pg_identify_object_as_address(classid, objid, objsubid) as addr + FROM deps +) s +ORDER BY obj COLLATE "C", ident::text COLLATE "C"; + obj | ident | addr +----------------------------------------------------------+----------------------------------------------------------------------------+---------------------------------------------------------------------------- + edge e of property graph gt | ("property graph element",,,"e of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,e}",{}) + edge e of property graph gt | ("property graph element",,,"e of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,e}",{}) + edge e of property graph gt | ("property graph element",,,"e of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of property graph gt | ("property graph label",,,"e of create_property_graph_tests.gt") | ("property graph label","{create_property_graph_tests,gt,e}",{}) + label v1 of property graph gt | ("property graph label",,,"v1 of create_property_graph_tests.gt") | ("property graph label","{create_property_graph_tests,gt,v1}",{}) + label v1 of vertex v1 of property graph gt | ("property graph element label",,,"v1 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v1}",{}) + label v1 of vertex v1 of property graph gt | ("property graph element label",,,"v1 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v1}",{}) + label v2 of property graph gt | ("property graph label",,,"v2 of create_property_graph_tests.gt") | ("property graph label","{create_property_graph_tests,gt,v2}",{}) + label v2 of vertex v2 of property graph gt | ("property graph element label",,,"v2 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v2}",{}) + label v2 of vertex v2 of property graph gt | ("property graph element label",,,"v2 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v2}",{}) + property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property a of property graph gt | ("property graph property",,,"a of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,a}",{}) + property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property b of property graph gt | ("property graph property",,,"b of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,b}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of property graph gt | ("property graph property",,,"c of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,c}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of property graph gt | ("property graph property",,,"k1 of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,k1}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of property graph gt | ("property graph property",,,"k2 of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,k2}",{}) + property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property m of property graph gt | ("property graph property",,,"m of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,m}",{}) + property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property n of property graph gt | ("property graph property",,,"n of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,n}",{}) + type gt | (type,create_property_graph_tests,gt,create_property_graph_tests.gt) | (type,{create_property_graph_tests.gt},{}) + type gt[] | (type,create_property_graph_tests,_gt,create_property_graph_tests.gt[]) | (type,{create_property_graph_tests.gt[]},{}) + vertex v1 of property graph gt | ("property graph element",,,"v1 of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,v1}",{}) + vertex v2 of property graph gt | ("property graph element",,,"v2 of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,v2}",{}) +(52 rows) + \a\t SELECT pg_get_propgraphdef('g2'::regclass); CREATE PROPERTY GRAPH create_property_graph_tests.g2 diff --git a/src/test/regress/expected/event_trigger.out b/src/test/regress/expected/event_trigger.out index 065f586310f..ed8d5df397e 100644 --- a/src/test/regress/expected/event_trigger.out +++ b/src/test/regress/expected/event_trigger.out @@ -173,6 +173,23 @@ NOTICE: test_event_trigger: ddl_command_end CREATE USER MAPPING alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; NOTICE: test_event_trigger: ddl_command_end ALTER DEFAULT PRIVILEGES +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE TABLE t2x (i int PRIMARY KEY, j text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); +NOTICE: test_event_trigger: ddl_command_end CREATE PROPERTY GRAPH +DROP PROPERTY GRAPH gx; +NOTICE: test_event_trigger: ddl_command_end DROP PROPERTY GRAPH +DROP TABLE t1x, t2x; +NOTICE: test_event_trigger: ddl_command_end DROP TABLE -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; ERROR: permission denied to change owner of event trigger "regress_event_trigger" diff --git a/src/test/regress/expected/object_address.out b/src/test/regress/expected/object_address.out index 97227d67a54..5e53f0b092e 100644 --- a/src/test/regress/expected/object_address.out +++ b/src/test/regress/expected/object_address.out @@ -67,7 +67,9 @@ DECLARE BEGIN FOR objtype IN VALUES ('toast table'), ('index column'), ('sequence column'), ('toast table column'), ('view column'), ('materialized view column'), - ('property graph element'), ('property graph label'), ('property graph property') + ('property graph element'), ('property graph element label'), + ('property graph label'), ('property graph label property'), + ('property graph property') LOOP BEGIN PERFORM pg_get_object_address(objtype, '{one}', '{}'); @@ -84,7 +86,9 @@ WARNING: error for toast table column: unsupported object type "toast table col WARNING: error for view column: unsupported object type "view column" WARNING: error for materialized view column: unsupported object type "materialized view column" WARNING: error for property graph element: unsupported object type "property graph element" +WARNING: error for property graph element label: unrecognized object type "property graph element label" WARNING: error for property graph label: unsupported object type "property graph label" +WARNING: error for property graph label property: unrecognized object type "property graph label property" WARNING: error for property graph property: unsupported object type "property graph property" -- miscellaneous other errors select * from pg_get_object_address('operator of access method', '{btree,integer_ops,1}', '{int4,bool}'); @@ -593,7 +597,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace @@ -653,6 +659,8 @@ ORDER BY objects.classid, objects.objid, objects.objsubid; ("(""parameter ACL"",,,)")|("(""parameter ACL"",,)")|NULL ("(""property graph element"",,,)")|("(""property graph element"",,)")|NULL ("(""property graph label"",,,)")|("(""property graph label"",,)")|NULL +("(""property graph element label"",,,)")|("(""property graph element label"",,)")|NULL ("(""property graph property"",,,)")|("(""property graph property"",,)")|NULL +("(""property graph label property"",,,)")|("(""property graph label property"",,)")|NULL -- restore normal output mode \a\t diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..9608dd5c4af 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -298,6 +298,29 @@ SELECT (pg_identify_object(classid, objid, objsubid)).* refobjid = 'create_property_graph_tests.g2'::regclass ORDER BY 1, 2, 3, 4; +-- test object address functions with recursive dependency walk +-- covers all property graph object types including indirect dependents +SELECT * +FROM ( + WITH RECURSIVE deps (classid, objid, objsubid, refclassid, refobjid, refobjsubid) AS ( + SELECT classid, objid, objsubid, + refclassid, refobjid, refobjsubid + FROM pg_depend + WHERE refclassid = 'pg_class'::regclass AND + refobjid = 'create_property_graph_tests.gt'::regclass + UNION ALL + SELECT d.classid, d.objid, d.objsubid, + d.refclassid, d.refobjid, d.refobjsubid + FROM pg_depend d + JOIN deps dp ON d.refclassid = dp.classid AND d.refobjid = dp.objid AND d.refobjsubid = dp.objsubid + ) + SELECT pg_describe_object(classid, objid, objsubid) as obj, + pg_identify_object(classid, objid, objsubid) as ident, + pg_identify_object_as_address(classid, objid, objsubid) as addr + FROM deps +) s +ORDER BY obj COLLATE "C", ident::text COLLATE "C"; + \a\t SELECT pg_get_propgraphdef('g2'::regclass); SELECT pg_get_propgraphdef('g3'::regclass); diff --git a/src/test/regress/sql/event_trigger.sql b/src/test/regress/sql/event_trigger.sql index 32e9bb58c5e..271f443378b 100644 --- a/src/test/regress/sql/event_trigger.sql +++ b/src/test/regress/sql/event_trigger.sql @@ -143,6 +143,19 @@ create user mapping for regress_evt_user server useless_server; alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +CREATE TABLE t2x (i int PRIMARY KEY, j text); + +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); + +DROP PROPERTY GRAPH gx; +DROP TABLE t1x, t2x; + -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; diff --git a/src/test/regress/sql/object_address.sql b/src/test/regress/sql/object_address.sql index 1bbe9457c1c..27109d421c7 100644 --- a/src/test/regress/sql/object_address.sql +++ b/src/test/regress/sql/object_address.sql @@ -67,7 +67,9 @@ DECLARE BEGIN FOR objtype IN VALUES ('toast table'), ('index column'), ('sequence column'), ('toast table column'), ('view column'), ('materialized view column'), - ('property graph element'), ('property graph label'), ('property graph property') + ('property graph element'), ('property graph element label'), + ('property graph label'), ('property graph label property'), + ('property graph property') LOOP BEGIN PERFORM pg_get_object_address(objtype, '{one}', '{}'); @@ -282,7 +284,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace -- 2.34.1 --R84XrR4Hgw0dH3Ec-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v2] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-23 09:27 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-23 09:27 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing them to hit the default case and error out with "unsupported object class". During DROP PROPERTY GRAPH, this manifests when an event trigger is active, because pg_event_trigger_ddl_commands() calls these functions. The same code paths are also reachable via pg_identify_object() and pg_identify_object_as_address(). This commit adds the missing cases. Test coverage is added in object_address.sql for these two catalog types via the zero-OID test that exercises pg_identify_object() and pg_identify_object_as_address(). A test in event_trigger.sql verifies that DROP PROPERTY GRAPH works correctly when an event trigger is active. Author: Bertrand Drouvot <[email protected]> Reviewed-by: Michael Paquier <[email protected]> Reviewed-by: Ashutosh Bapat <[email protected]> Discussion: https://postgr.es/m/aej1DkLwhyZWmtxJ@bdtpg --- src/backend/catalog/objectaddress.c | 93 ++++++++++++++++++++ src/test/regress/expected/event_trigger.out | 17 ++++ src/test/regress/expected/object_address.out | 4 + src/test/regress/sql/event_trigger.sql | 13 +++ src/test/regress/sql/object_address.sql | 2 + 5 files changed, 129 insertions(+) 62.4% src/backend/catalog/ 25.6% src/test/regress/expected/ 11.8% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/event_trigger.out b/src/test/regress/expected/event_trigger.out index 065f586310f..ed8d5df397e 100644 --- a/src/test/regress/expected/event_trigger.out +++ b/src/test/regress/expected/event_trigger.out @@ -173,6 +173,23 @@ NOTICE: test_event_trigger: ddl_command_end CREATE USER MAPPING alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; NOTICE: test_event_trigger: ddl_command_end ALTER DEFAULT PRIVILEGES +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE TABLE t2x (i int PRIMARY KEY, j text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); +NOTICE: test_event_trigger: ddl_command_end CREATE PROPERTY GRAPH +DROP PROPERTY GRAPH gx; +NOTICE: test_event_trigger: ddl_command_end DROP PROPERTY GRAPH +DROP TABLE t1x, t2x; +NOTICE: test_event_trigger: ddl_command_end DROP TABLE -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; ERROR: permission denied to change owner of event trigger "regress_event_trigger" diff --git a/src/test/regress/expected/object_address.out b/src/test/regress/expected/object_address.out index 97227d67a54..729c3537f25 100644 --- a/src/test/regress/expected/object_address.out +++ b/src/test/regress/expected/object_address.out @@ -593,7 +593,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace @@ -653,6 +655,8 @@ ORDER BY objects.classid, objects.objid, objects.objsubid; ("(""parameter ACL"",,,)")|("(""parameter ACL"",,)")|NULL ("(""property graph element"",,,)")|("(""property graph element"",,)")|NULL ("(""property graph label"",,,)")|("(""property graph label"",,)")|NULL +("(""property graph element label"",,,)")|("(""property graph element label"",,)")|NULL ("(""property graph property"",,,)")|("(""property graph property"",,)")|NULL +("(""property graph label property"",,,)")|("(""property graph label property"",,)")|NULL -- restore normal output mode \a\t diff --git a/src/test/regress/sql/event_trigger.sql b/src/test/regress/sql/event_trigger.sql index 32e9bb58c5e..271f443378b 100644 --- a/src/test/regress/sql/event_trigger.sql +++ b/src/test/regress/sql/event_trigger.sql @@ -143,6 +143,19 @@ create user mapping for regress_evt_user server useless_server; alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +CREATE TABLE t2x (i int PRIMARY KEY, j text); + +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); + +DROP PROPERTY GRAPH gx; +DROP TABLE t1x, t2x; + -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; diff --git a/src/test/regress/sql/object_address.sql b/src/test/regress/sql/object_address.sql index 1bbe9457c1c..620dacf1045 100644 --- a/src/test/regress/sql/object_address.sql +++ b/src/test/regress/sql/object_address.sql @@ -282,7 +282,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace -- 2.34.1 --gtUR827Uq8d5gVsQ-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v2] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-23 09:27 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-23 09:27 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing them to hit the default case and error out with "unsupported object class". During DROP PROPERTY GRAPH, this manifests when an event trigger is active, because pg_event_trigger_ddl_commands() calls these functions. The same code paths are also reachable via pg_identify_object() and pg_identify_object_as_address(). This commit adds the missing cases. Test coverage is added in object_address.sql for these two catalog types via the zero-OID test that exercises pg_identify_object() and pg_identify_object_as_address(). A test in event_trigger.sql verifies that DROP PROPERTY GRAPH works correctly when an event trigger is active. Author: Bertrand Drouvot <[email protected]> Reviewed-by: Michael Paquier <[email protected]> Reviewed-by: Ashutosh Bapat <[email protected]> Discussion: https://postgr.es/m/aej1DkLwhyZWmtxJ@bdtpg --- src/backend/catalog/objectaddress.c | 93 ++++++++++++++++++++ src/test/regress/expected/event_trigger.out | 17 ++++ src/test/regress/expected/object_address.out | 4 + src/test/regress/sql/event_trigger.sql | 13 +++ src/test/regress/sql/object_address.sql | 2 + 5 files changed, 129 insertions(+) 62.4% src/backend/catalog/ 25.6% src/test/regress/expected/ 11.8% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/event_trigger.out b/src/test/regress/expected/event_trigger.out index 065f586310f..ed8d5df397e 100644 --- a/src/test/regress/expected/event_trigger.out +++ b/src/test/regress/expected/event_trigger.out @@ -173,6 +173,23 @@ NOTICE: test_event_trigger: ddl_command_end CREATE USER MAPPING alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; NOTICE: test_event_trigger: ddl_command_end ALTER DEFAULT PRIVILEGES +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE TABLE t2x (i int PRIMARY KEY, j text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); +NOTICE: test_event_trigger: ddl_command_end CREATE PROPERTY GRAPH +DROP PROPERTY GRAPH gx; +NOTICE: test_event_trigger: ddl_command_end DROP PROPERTY GRAPH +DROP TABLE t1x, t2x; +NOTICE: test_event_trigger: ddl_command_end DROP TABLE -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; ERROR: permission denied to change owner of event trigger "regress_event_trigger" diff --git a/src/test/regress/expected/object_address.out b/src/test/regress/expected/object_address.out index 97227d67a54..729c3537f25 100644 --- a/src/test/regress/expected/object_address.out +++ b/src/test/regress/expected/object_address.out @@ -593,7 +593,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace @@ -653,6 +655,8 @@ ORDER BY objects.classid, objects.objid, objects.objsubid; ("(""parameter ACL"",,,)")|("(""parameter ACL"",,)")|NULL ("(""property graph element"",,,)")|("(""property graph element"",,)")|NULL ("(""property graph label"",,,)")|("(""property graph label"",,)")|NULL +("(""property graph element label"",,,)")|("(""property graph element label"",,)")|NULL ("(""property graph property"",,,)")|("(""property graph property"",,)")|NULL +("(""property graph label property"",,,)")|("(""property graph label property"",,)")|NULL -- restore normal output mode \a\t diff --git a/src/test/regress/sql/event_trigger.sql b/src/test/regress/sql/event_trigger.sql index 32e9bb58c5e..271f443378b 100644 --- a/src/test/regress/sql/event_trigger.sql +++ b/src/test/regress/sql/event_trigger.sql @@ -143,6 +143,19 @@ create user mapping for regress_evt_user server useless_server; alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +CREATE TABLE t2x (i int PRIMARY KEY, j text); + +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); + +DROP PROPERTY GRAPH gx; +DROP TABLE t1x, t2x; + -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; diff --git a/src/test/regress/sql/object_address.sql b/src/test/regress/sql/object_address.sql index 1bbe9457c1c..620dacf1045 100644 --- a/src/test/regress/sql/object_address.sql +++ b/src/test/regress/sql/object_address.sql @@ -282,7 +282,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace -- 2.34.1 --gtUR827Uq8d5gVsQ-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v2] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-23 09:27 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-23 09:27 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing them to hit the default case and error out with "unsupported object class". During DROP PROPERTY GRAPH, this manifests when an event trigger is active, because pg_event_trigger_ddl_commands() calls these functions. The same code paths are also reachable via pg_identify_object() and pg_identify_object_as_address(). This commit adds the missing cases. Test coverage is added in object_address.sql for these two catalog types via the zero-OID test that exercises pg_identify_object() and pg_identify_object_as_address(). A test in event_trigger.sql verifies that DROP PROPERTY GRAPH works correctly when an event trigger is active. Author: Bertrand Drouvot <[email protected]> Reviewed-by: Michael Paquier <[email protected]> Reviewed-by: Ashutosh Bapat <[email protected]> Discussion: https://postgr.es/m/aej1DkLwhyZWmtxJ@bdtpg --- src/backend/catalog/objectaddress.c | 93 ++++++++++++++++++++ src/test/regress/expected/event_trigger.out | 17 ++++ src/test/regress/expected/object_address.out | 4 + src/test/regress/sql/event_trigger.sql | 13 +++ src/test/regress/sql/object_address.sql | 2 + 5 files changed, 129 insertions(+) 62.4% src/backend/catalog/ 25.6% src/test/regress/expected/ 11.8% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/event_trigger.out b/src/test/regress/expected/event_trigger.out index 065f586310f..ed8d5df397e 100644 --- a/src/test/regress/expected/event_trigger.out +++ b/src/test/regress/expected/event_trigger.out @@ -173,6 +173,23 @@ NOTICE: test_event_trigger: ddl_command_end CREATE USER MAPPING alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; NOTICE: test_event_trigger: ddl_command_end ALTER DEFAULT PRIVILEGES +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE TABLE t2x (i int PRIMARY KEY, j text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); +NOTICE: test_event_trigger: ddl_command_end CREATE PROPERTY GRAPH +DROP PROPERTY GRAPH gx; +NOTICE: test_event_trigger: ddl_command_end DROP PROPERTY GRAPH +DROP TABLE t1x, t2x; +NOTICE: test_event_trigger: ddl_command_end DROP TABLE -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; ERROR: permission denied to change owner of event trigger "regress_event_trigger" diff --git a/src/test/regress/expected/object_address.out b/src/test/regress/expected/object_address.out index 97227d67a54..729c3537f25 100644 --- a/src/test/regress/expected/object_address.out +++ b/src/test/regress/expected/object_address.out @@ -593,7 +593,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace @@ -653,6 +655,8 @@ ORDER BY objects.classid, objects.objid, objects.objsubid; ("(""parameter ACL"",,,)")|("(""parameter ACL"",,)")|NULL ("(""property graph element"",,,)")|("(""property graph element"",,)")|NULL ("(""property graph label"",,,)")|("(""property graph label"",,)")|NULL +("(""property graph element label"",,,)")|("(""property graph element label"",,)")|NULL ("(""property graph property"",,,)")|("(""property graph property"",,)")|NULL +("(""property graph label property"",,,)")|("(""property graph label property"",,)")|NULL -- restore normal output mode \a\t diff --git a/src/test/regress/sql/event_trigger.sql b/src/test/regress/sql/event_trigger.sql index 32e9bb58c5e..271f443378b 100644 --- a/src/test/regress/sql/event_trigger.sql +++ b/src/test/regress/sql/event_trigger.sql @@ -143,6 +143,19 @@ create user mapping for regress_evt_user server useless_server; alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +CREATE TABLE t2x (i int PRIMARY KEY, j text); + +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); + +DROP PROPERTY GRAPH gx; +DROP TABLE t1x, t2x; + -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; diff --git a/src/test/regress/sql/object_address.sql b/src/test/regress/sql/object_address.sql index 1bbe9457c1c..620dacf1045 100644 --- a/src/test/regress/sql/object_address.sql +++ b/src/test/regress/sql/object_address.sql @@ -282,7 +282,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace -- 2.34.1 --gtUR827Uq8d5gVsQ-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v2] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-23 09:27 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-23 09:27 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing them to hit the default case and error out with "unsupported object class". During DROP PROPERTY GRAPH, this manifests when an event trigger is active, because pg_event_trigger_ddl_commands() calls these functions. The same code paths are also reachable via pg_identify_object() and pg_identify_object_as_address(). This commit adds the missing cases. Test coverage is added in object_address.sql for these two catalog types via the zero-OID test that exercises pg_identify_object() and pg_identify_object_as_address(). A test in event_trigger.sql verifies that DROP PROPERTY GRAPH works correctly when an event trigger is active. Author: Bertrand Drouvot <[email protected]> Reviewed-by: Michael Paquier <[email protected]> Reviewed-by: Ashutosh Bapat <[email protected]> Discussion: https://postgr.es/m/aej1DkLwhyZWmtxJ@bdtpg --- src/backend/catalog/objectaddress.c | 93 ++++++++++++++++++++ src/test/regress/expected/event_trigger.out | 17 ++++ src/test/regress/expected/object_address.out | 4 + src/test/regress/sql/event_trigger.sql | 13 +++ src/test/regress/sql/object_address.sql | 2 + 5 files changed, 129 insertions(+) 62.4% src/backend/catalog/ 25.6% src/test/regress/expected/ 11.8% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/event_trigger.out b/src/test/regress/expected/event_trigger.out index 065f586310f..ed8d5df397e 100644 --- a/src/test/regress/expected/event_trigger.out +++ b/src/test/regress/expected/event_trigger.out @@ -173,6 +173,23 @@ NOTICE: test_event_trigger: ddl_command_end CREATE USER MAPPING alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; NOTICE: test_event_trigger: ddl_command_end ALTER DEFAULT PRIVILEGES +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE TABLE t2x (i int PRIMARY KEY, j text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); +NOTICE: test_event_trigger: ddl_command_end CREATE PROPERTY GRAPH +DROP PROPERTY GRAPH gx; +NOTICE: test_event_trigger: ddl_command_end DROP PROPERTY GRAPH +DROP TABLE t1x, t2x; +NOTICE: test_event_trigger: ddl_command_end DROP TABLE -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; ERROR: permission denied to change owner of event trigger "regress_event_trigger" diff --git a/src/test/regress/expected/object_address.out b/src/test/regress/expected/object_address.out index 97227d67a54..729c3537f25 100644 --- a/src/test/regress/expected/object_address.out +++ b/src/test/regress/expected/object_address.out @@ -593,7 +593,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace @@ -653,6 +655,8 @@ ORDER BY objects.classid, objects.objid, objects.objsubid; ("(""parameter ACL"",,,)")|("(""parameter ACL"",,)")|NULL ("(""property graph element"",,,)")|("(""property graph element"",,)")|NULL ("(""property graph label"",,,)")|("(""property graph label"",,)")|NULL +("(""property graph element label"",,,)")|("(""property graph element label"",,)")|NULL ("(""property graph property"",,,)")|("(""property graph property"",,)")|NULL +("(""property graph label property"",,,)")|("(""property graph label property"",,)")|NULL -- restore normal output mode \a\t diff --git a/src/test/regress/sql/event_trigger.sql b/src/test/regress/sql/event_trigger.sql index 32e9bb58c5e..271f443378b 100644 --- a/src/test/regress/sql/event_trigger.sql +++ b/src/test/regress/sql/event_trigger.sql @@ -143,6 +143,19 @@ create user mapping for regress_evt_user server useless_server; alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +CREATE TABLE t2x (i int PRIMARY KEY, j text); + +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); + +DROP PROPERTY GRAPH gx; +DROP TABLE t1x, t2x; + -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; diff --git a/src/test/regress/sql/object_address.sql b/src/test/regress/sql/object_address.sql index 1bbe9457c1c..620dacf1045 100644 --- a/src/test/regress/sql/object_address.sql +++ b/src/test/regress/sql/object_address.sql @@ -282,7 +282,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace -- 2.34.1 --gtUR827Uq8d5gVsQ-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v3] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-23 09:27 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-23 09:27 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing them to hit the default case and error out with "unsupported object class". During DROP PROPERTY GRAPH, this manifests when an event trigger is active, because pg_event_trigger_ddl_commands() calls these functions. The same code paths are also reachable via pg_identify_object() and pg_identify_object_as_address(). This commit adds the missing cases. Test coverage is added in object_address.sql for these two catalog types and in create_property_graph.sql covering all property graph object types. A test in event_trigger.sql verifies that DROP PROPERTY GRAPH works correctly when an event trigger is active. Author: Bertrand Drouvot <[email protected]> Reviewed-by: Michael Paquier <[email protected]> Reviewed-by: Ashutosh Bapat <[email protected]> Discussion: https://postgr.es/m/aej1DkLwhyZWmtxJ@bdtpg --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 78 ++++++++++++++++ src/test/regress/expected/event_trigger.out | 17 ++++ src/test/regress/expected/object_address.out | 10 +- .../regress/sql/create_property_graph.sql | 23 +++++ src/test/regress/sql/event_trigger.sql | 13 +++ src/test/regress/sql/object_address.sql | 6 +- 7 files changed, 238 insertions(+), 2 deletions(-) 14.7% src/backend/catalog/ 75.5% src/test/regress/expected/ 9.7% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..eb9e17fb727 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -752,6 +752,84 @@ SELECT (pg_identify_object(classid, objid, objsubid)).* type | create_property_graph_tests | g2 | create_property_graph_tests.g2 (21 rows) +-- test object address functions with recursive dependency walk +-- covers all property graph object types including indirect dependents +SELECT * +FROM ( + WITH RECURSIVE deps (classid, objid, objsubid, refclassid, refobjid, refobjsubid) AS ( + SELECT classid, objid, objsubid, + refclassid, refobjid, refobjsubid + FROM pg_depend + WHERE refclassid = 'pg_class'::regclass AND + refobjid = 'create_property_graph_tests.gt'::regclass + UNION ALL + SELECT d.classid, d.objid, d.objsubid, + d.refclassid, d.refobjid, d.refobjsubid + FROM pg_depend d + JOIN deps dp ON d.refclassid = dp.classid AND d.refobjid = dp.objid AND d.refobjsubid = dp.objsubid + ) + SELECT pg_describe_object(classid, objid, objsubid) as obj, + pg_identify_object(classid, objid, objsubid) as ident, + pg_identify_object_as_address(classid, objid, objsubid) as addr + FROM deps +) s +ORDER BY obj COLLATE "C", ident::text COLLATE "C"; + obj | ident | addr +----------------------------------------------------------+----------------------------------------------------------------------------+---------------------------------------------------------------------------- + edge e of property graph gt | ("property graph element",,,"e of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,e}",{}) + edge e of property graph gt | ("property graph element",,,"e of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,e}",{}) + edge e of property graph gt | ("property graph element",,,"e of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of property graph gt | ("property graph label",,,"e of create_property_graph_tests.gt") | ("property graph label","{create_property_graph_tests,gt,e}",{}) + label v1 of property graph gt | ("property graph label",,,"v1 of create_property_graph_tests.gt") | ("property graph label","{create_property_graph_tests,gt,v1}",{}) + label v1 of vertex v1 of property graph gt | ("property graph element label",,,"v1 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v1}",{}) + label v1 of vertex v1 of property graph gt | ("property graph element label",,,"v1 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v1}",{}) + label v2 of property graph gt | ("property graph label",,,"v2 of create_property_graph_tests.gt") | ("property graph label","{create_property_graph_tests,gt,v2}",{}) + label v2 of vertex v2 of property graph gt | ("property graph element label",,,"v2 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v2}",{}) + label v2 of vertex v2 of property graph gt | ("property graph element label",,,"v2 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v2}",{}) + property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property a of property graph gt | ("property graph property",,,"a of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,a}",{}) + property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property b of property graph gt | ("property graph property",,,"b of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,b}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of property graph gt | ("property graph property",,,"c of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,c}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of property graph gt | ("property graph property",,,"k1 of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,k1}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of property graph gt | ("property graph property",,,"k2 of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,k2}",{}) + property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property m of property graph gt | ("property graph property",,,"m of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,m}",{}) + property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property n of property graph gt | ("property graph property",,,"n of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,n}",{}) + type gt | (type,create_property_graph_tests,gt,create_property_graph_tests.gt) | (type,{create_property_graph_tests.gt},{}) + type gt[] | (type,create_property_graph_tests,_gt,create_property_graph_tests.gt[]) | (type,{create_property_graph_tests.gt[]},{}) + vertex v1 of property graph gt | ("property graph element",,,"v1 of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,v1}",{}) + vertex v2 of property graph gt | ("property graph element",,,"v2 of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,v2}",{}) +(52 rows) + \a\t SELECT pg_get_propgraphdef('g2'::regclass); CREATE PROPERTY GRAPH create_property_graph_tests.g2 diff --git a/src/test/regress/expected/event_trigger.out b/src/test/regress/expected/event_trigger.out index 065f586310f..ed8d5df397e 100644 --- a/src/test/regress/expected/event_trigger.out +++ b/src/test/regress/expected/event_trigger.out @@ -173,6 +173,23 @@ NOTICE: test_event_trigger: ddl_command_end CREATE USER MAPPING alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; NOTICE: test_event_trigger: ddl_command_end ALTER DEFAULT PRIVILEGES +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE TABLE t2x (i int PRIMARY KEY, j text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); +NOTICE: test_event_trigger: ddl_command_end CREATE PROPERTY GRAPH +DROP PROPERTY GRAPH gx; +NOTICE: test_event_trigger: ddl_command_end DROP PROPERTY GRAPH +DROP TABLE t1x, t2x; +NOTICE: test_event_trigger: ddl_command_end DROP TABLE -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; ERROR: permission denied to change owner of event trigger "regress_event_trigger" diff --git a/src/test/regress/expected/object_address.out b/src/test/regress/expected/object_address.out index 97227d67a54..5e53f0b092e 100644 --- a/src/test/regress/expected/object_address.out +++ b/src/test/regress/expected/object_address.out @@ -67,7 +67,9 @@ DECLARE BEGIN FOR objtype IN VALUES ('toast table'), ('index column'), ('sequence column'), ('toast table column'), ('view column'), ('materialized view column'), - ('property graph element'), ('property graph label'), ('property graph property') + ('property graph element'), ('property graph element label'), + ('property graph label'), ('property graph label property'), + ('property graph property') LOOP BEGIN PERFORM pg_get_object_address(objtype, '{one}', '{}'); @@ -84,7 +86,9 @@ WARNING: error for toast table column: unsupported object type "toast table col WARNING: error for view column: unsupported object type "view column" WARNING: error for materialized view column: unsupported object type "materialized view column" WARNING: error for property graph element: unsupported object type "property graph element" +WARNING: error for property graph element label: unrecognized object type "property graph element label" WARNING: error for property graph label: unsupported object type "property graph label" +WARNING: error for property graph label property: unrecognized object type "property graph label property" WARNING: error for property graph property: unsupported object type "property graph property" -- miscellaneous other errors select * from pg_get_object_address('operator of access method', '{btree,integer_ops,1}', '{int4,bool}'); @@ -593,7 +597,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace @@ -653,6 +659,8 @@ ORDER BY objects.classid, objects.objid, objects.objsubid; ("(""parameter ACL"",,,)")|("(""parameter ACL"",,)")|NULL ("(""property graph element"",,,)")|("(""property graph element"",,)")|NULL ("(""property graph label"",,,)")|("(""property graph label"",,)")|NULL +("(""property graph element label"",,,)")|("(""property graph element label"",,)")|NULL ("(""property graph property"",,,)")|("(""property graph property"",,)")|NULL +("(""property graph label property"",,,)")|("(""property graph label property"",,)")|NULL -- restore normal output mode \a\t diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..9608dd5c4af 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -298,6 +298,29 @@ SELECT (pg_identify_object(classid, objid, objsubid)).* refobjid = 'create_property_graph_tests.g2'::regclass ORDER BY 1, 2, 3, 4; +-- test object address functions with recursive dependency walk +-- covers all property graph object types including indirect dependents +SELECT * +FROM ( + WITH RECURSIVE deps (classid, objid, objsubid, refclassid, refobjid, refobjsubid) AS ( + SELECT classid, objid, objsubid, + refclassid, refobjid, refobjsubid + FROM pg_depend + WHERE refclassid = 'pg_class'::regclass AND + refobjid = 'create_property_graph_tests.gt'::regclass + UNION ALL + SELECT d.classid, d.objid, d.objsubid, + d.refclassid, d.refobjid, d.refobjsubid + FROM pg_depend d + JOIN deps dp ON d.refclassid = dp.classid AND d.refobjid = dp.objid AND d.refobjsubid = dp.objsubid + ) + SELECT pg_describe_object(classid, objid, objsubid) as obj, + pg_identify_object(classid, objid, objsubid) as ident, + pg_identify_object_as_address(classid, objid, objsubid) as addr + FROM deps +) s +ORDER BY obj COLLATE "C", ident::text COLLATE "C"; + \a\t SELECT pg_get_propgraphdef('g2'::regclass); SELECT pg_get_propgraphdef('g3'::regclass); diff --git a/src/test/regress/sql/event_trigger.sql b/src/test/regress/sql/event_trigger.sql index 32e9bb58c5e..271f443378b 100644 --- a/src/test/regress/sql/event_trigger.sql +++ b/src/test/regress/sql/event_trigger.sql @@ -143,6 +143,19 @@ create user mapping for regress_evt_user server useless_server; alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +CREATE TABLE t2x (i int PRIMARY KEY, j text); + +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); + +DROP PROPERTY GRAPH gx; +DROP TABLE t1x, t2x; + -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; diff --git a/src/test/regress/sql/object_address.sql b/src/test/regress/sql/object_address.sql index 1bbe9457c1c..27109d421c7 100644 --- a/src/test/regress/sql/object_address.sql +++ b/src/test/regress/sql/object_address.sql @@ -67,7 +67,9 @@ DECLARE BEGIN FOR objtype IN VALUES ('toast table'), ('index column'), ('sequence column'), ('toast table column'), ('view column'), ('materialized view column'), - ('property graph element'), ('property graph label'), ('property graph property') + ('property graph element'), ('property graph element label'), + ('property graph label'), ('property graph label property'), + ('property graph property') LOOP BEGIN PERFORM pg_get_object_address(objtype, '{one}', '{}'); @@ -282,7 +284,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace -- 2.34.1 --R84XrR4Hgw0dH3Ec-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v3] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-23 09:27 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-23 09:27 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing them to hit the default case and error out with "unsupported object class". During DROP PROPERTY GRAPH, this manifests when an event trigger is active, because pg_event_trigger_ddl_commands() calls these functions. The same code paths are also reachable via pg_identify_object() and pg_identify_object_as_address(). This commit adds the missing cases. Test coverage is added in object_address.sql for these two catalog types and in create_property_graph.sql covering all property graph object types. A test in event_trigger.sql verifies that DROP PROPERTY GRAPH works correctly when an event trigger is active. Author: Bertrand Drouvot <[email protected]> Reviewed-by: Michael Paquier <[email protected]> Reviewed-by: Ashutosh Bapat <[email protected]> Discussion: https://postgr.es/m/aej1DkLwhyZWmtxJ@bdtpg --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 78 ++++++++++++++++ src/test/regress/expected/event_trigger.out | 17 ++++ src/test/regress/expected/object_address.out | 10 +- .../regress/sql/create_property_graph.sql | 23 +++++ src/test/regress/sql/event_trigger.sql | 13 +++ src/test/regress/sql/object_address.sql | 6 +- 7 files changed, 238 insertions(+), 2 deletions(-) 14.7% src/backend/catalog/ 75.5% src/test/regress/expected/ 9.7% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..eb9e17fb727 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -752,6 +752,84 @@ SELECT (pg_identify_object(classid, objid, objsubid)).* type | create_property_graph_tests | g2 | create_property_graph_tests.g2 (21 rows) +-- test object address functions with recursive dependency walk +-- covers all property graph object types including indirect dependents +SELECT * +FROM ( + WITH RECURSIVE deps (classid, objid, objsubid, refclassid, refobjid, refobjsubid) AS ( + SELECT classid, objid, objsubid, + refclassid, refobjid, refobjsubid + FROM pg_depend + WHERE refclassid = 'pg_class'::regclass AND + refobjid = 'create_property_graph_tests.gt'::regclass + UNION ALL + SELECT d.classid, d.objid, d.objsubid, + d.refclassid, d.refobjid, d.refobjsubid + FROM pg_depend d + JOIN deps dp ON d.refclassid = dp.classid AND d.refobjid = dp.objid AND d.refobjsubid = dp.objsubid + ) + SELECT pg_describe_object(classid, objid, objsubid) as obj, + pg_identify_object(classid, objid, objsubid) as ident, + pg_identify_object_as_address(classid, objid, objsubid) as addr + FROM deps +) s +ORDER BY obj COLLATE "C", ident::text COLLATE "C"; + obj | ident | addr +----------------------------------------------------------+----------------------------------------------------------------------------+---------------------------------------------------------------------------- + edge e of property graph gt | ("property graph element",,,"e of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,e}",{}) + edge e of property graph gt | ("property graph element",,,"e of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,e}",{}) + edge e of property graph gt | ("property graph element",,,"e of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of property graph gt | ("property graph label",,,"e of create_property_graph_tests.gt") | ("property graph label","{create_property_graph_tests,gt,e}",{}) + label v1 of property graph gt | ("property graph label",,,"v1 of create_property_graph_tests.gt") | ("property graph label","{create_property_graph_tests,gt,v1}",{}) + label v1 of vertex v1 of property graph gt | ("property graph element label",,,"v1 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v1}",{}) + label v1 of vertex v1 of property graph gt | ("property graph element label",,,"v1 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v1}",{}) + label v2 of property graph gt | ("property graph label",,,"v2 of create_property_graph_tests.gt") | ("property graph label","{create_property_graph_tests,gt,v2}",{}) + label v2 of vertex v2 of property graph gt | ("property graph element label",,,"v2 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v2}",{}) + label v2 of vertex v2 of property graph gt | ("property graph element label",,,"v2 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v2}",{}) + property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property a of property graph gt | ("property graph property",,,"a of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,a}",{}) + property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property b of property graph gt | ("property graph property",,,"b of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,b}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of property graph gt | ("property graph property",,,"c of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,c}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of property graph gt | ("property graph property",,,"k1 of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,k1}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of property graph gt | ("property graph property",,,"k2 of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,k2}",{}) + property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property m of property graph gt | ("property graph property",,,"m of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,m}",{}) + property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property n of property graph gt | ("property graph property",,,"n of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,n}",{}) + type gt | (type,create_property_graph_tests,gt,create_property_graph_tests.gt) | (type,{create_property_graph_tests.gt},{}) + type gt[] | (type,create_property_graph_tests,_gt,create_property_graph_tests.gt[]) | (type,{create_property_graph_tests.gt[]},{}) + vertex v1 of property graph gt | ("property graph element",,,"v1 of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,v1}",{}) + vertex v2 of property graph gt | ("property graph element",,,"v2 of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,v2}",{}) +(52 rows) + \a\t SELECT pg_get_propgraphdef('g2'::regclass); CREATE PROPERTY GRAPH create_property_graph_tests.g2 diff --git a/src/test/regress/expected/event_trigger.out b/src/test/regress/expected/event_trigger.out index 065f586310f..ed8d5df397e 100644 --- a/src/test/regress/expected/event_trigger.out +++ b/src/test/regress/expected/event_trigger.out @@ -173,6 +173,23 @@ NOTICE: test_event_trigger: ddl_command_end CREATE USER MAPPING alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; NOTICE: test_event_trigger: ddl_command_end ALTER DEFAULT PRIVILEGES +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE TABLE t2x (i int PRIMARY KEY, j text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); +NOTICE: test_event_trigger: ddl_command_end CREATE PROPERTY GRAPH +DROP PROPERTY GRAPH gx; +NOTICE: test_event_trigger: ddl_command_end DROP PROPERTY GRAPH +DROP TABLE t1x, t2x; +NOTICE: test_event_trigger: ddl_command_end DROP TABLE -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; ERROR: permission denied to change owner of event trigger "regress_event_trigger" diff --git a/src/test/regress/expected/object_address.out b/src/test/regress/expected/object_address.out index 97227d67a54..5e53f0b092e 100644 --- a/src/test/regress/expected/object_address.out +++ b/src/test/regress/expected/object_address.out @@ -67,7 +67,9 @@ DECLARE BEGIN FOR objtype IN VALUES ('toast table'), ('index column'), ('sequence column'), ('toast table column'), ('view column'), ('materialized view column'), - ('property graph element'), ('property graph label'), ('property graph property') + ('property graph element'), ('property graph element label'), + ('property graph label'), ('property graph label property'), + ('property graph property') LOOP BEGIN PERFORM pg_get_object_address(objtype, '{one}', '{}'); @@ -84,7 +86,9 @@ WARNING: error for toast table column: unsupported object type "toast table col WARNING: error for view column: unsupported object type "view column" WARNING: error for materialized view column: unsupported object type "materialized view column" WARNING: error for property graph element: unsupported object type "property graph element" +WARNING: error for property graph element label: unrecognized object type "property graph element label" WARNING: error for property graph label: unsupported object type "property graph label" +WARNING: error for property graph label property: unrecognized object type "property graph label property" WARNING: error for property graph property: unsupported object type "property graph property" -- miscellaneous other errors select * from pg_get_object_address('operator of access method', '{btree,integer_ops,1}', '{int4,bool}'); @@ -593,7 +597,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace @@ -653,6 +659,8 @@ ORDER BY objects.classid, objects.objid, objects.objsubid; ("(""parameter ACL"",,,)")|("(""parameter ACL"",,)")|NULL ("(""property graph element"",,,)")|("(""property graph element"",,)")|NULL ("(""property graph label"",,,)")|("(""property graph label"",,)")|NULL +("(""property graph element label"",,,)")|("(""property graph element label"",,)")|NULL ("(""property graph property"",,,)")|("(""property graph property"",,)")|NULL +("(""property graph label property"",,,)")|("(""property graph label property"",,)")|NULL -- restore normal output mode \a\t diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..9608dd5c4af 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -298,6 +298,29 @@ SELECT (pg_identify_object(classid, objid, objsubid)).* refobjid = 'create_property_graph_tests.g2'::regclass ORDER BY 1, 2, 3, 4; +-- test object address functions with recursive dependency walk +-- covers all property graph object types including indirect dependents +SELECT * +FROM ( + WITH RECURSIVE deps (classid, objid, objsubid, refclassid, refobjid, refobjsubid) AS ( + SELECT classid, objid, objsubid, + refclassid, refobjid, refobjsubid + FROM pg_depend + WHERE refclassid = 'pg_class'::regclass AND + refobjid = 'create_property_graph_tests.gt'::regclass + UNION ALL + SELECT d.classid, d.objid, d.objsubid, + d.refclassid, d.refobjid, d.refobjsubid + FROM pg_depend d + JOIN deps dp ON d.refclassid = dp.classid AND d.refobjid = dp.objid AND d.refobjsubid = dp.objsubid + ) + SELECT pg_describe_object(classid, objid, objsubid) as obj, + pg_identify_object(classid, objid, objsubid) as ident, + pg_identify_object_as_address(classid, objid, objsubid) as addr + FROM deps +) s +ORDER BY obj COLLATE "C", ident::text COLLATE "C"; + \a\t SELECT pg_get_propgraphdef('g2'::regclass); SELECT pg_get_propgraphdef('g3'::regclass); diff --git a/src/test/regress/sql/event_trigger.sql b/src/test/regress/sql/event_trigger.sql index 32e9bb58c5e..271f443378b 100644 --- a/src/test/regress/sql/event_trigger.sql +++ b/src/test/regress/sql/event_trigger.sql @@ -143,6 +143,19 @@ create user mapping for regress_evt_user server useless_server; alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +CREATE TABLE t2x (i int PRIMARY KEY, j text); + +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); + +DROP PROPERTY GRAPH gx; +DROP TABLE t1x, t2x; + -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; diff --git a/src/test/regress/sql/object_address.sql b/src/test/regress/sql/object_address.sql index 1bbe9457c1c..27109d421c7 100644 --- a/src/test/regress/sql/object_address.sql +++ b/src/test/regress/sql/object_address.sql @@ -67,7 +67,9 @@ DECLARE BEGIN FOR objtype IN VALUES ('toast table'), ('index column'), ('sequence column'), ('toast table column'), ('view column'), ('materialized view column'), - ('property graph element'), ('property graph label'), ('property graph property') + ('property graph element'), ('property graph element label'), + ('property graph label'), ('property graph label property'), + ('property graph property') LOOP BEGIN PERFORM pg_get_object_address(objtype, '{one}', '{}'); @@ -282,7 +284,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace -- 2.34.1 --R84XrR4Hgw0dH3Ec-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v2] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-23 09:27 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-23 09:27 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing them to hit the default case and error out with "unsupported object class". During DROP PROPERTY GRAPH, this manifests when an event trigger is active, because pg_event_trigger_ddl_commands() calls these functions. The same code paths are also reachable via pg_identify_object() and pg_identify_object_as_address(). This commit adds the missing cases. Test coverage is added in object_address.sql for these two catalog types via the zero-OID test that exercises pg_identify_object() and pg_identify_object_as_address(). A test in event_trigger.sql verifies that DROP PROPERTY GRAPH works correctly when an event trigger is active. Author: Bertrand Drouvot <[email protected]> Reviewed-by: Michael Paquier <[email protected]> Reviewed-by: Ashutosh Bapat <[email protected]> Discussion: https://postgr.es/m/aej1DkLwhyZWmtxJ@bdtpg --- src/backend/catalog/objectaddress.c | 93 ++++++++++++++++++++ src/test/regress/expected/event_trigger.out | 17 ++++ src/test/regress/expected/object_address.out | 4 + src/test/regress/sql/event_trigger.sql | 13 +++ src/test/regress/sql/object_address.sql | 2 + 5 files changed, 129 insertions(+) 62.4% src/backend/catalog/ 25.6% src/test/regress/expected/ 11.8% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/event_trigger.out b/src/test/regress/expected/event_trigger.out index 065f586310f..ed8d5df397e 100644 --- a/src/test/regress/expected/event_trigger.out +++ b/src/test/regress/expected/event_trigger.out @@ -173,6 +173,23 @@ NOTICE: test_event_trigger: ddl_command_end CREATE USER MAPPING alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; NOTICE: test_event_trigger: ddl_command_end ALTER DEFAULT PRIVILEGES +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE TABLE t2x (i int PRIMARY KEY, j text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); +NOTICE: test_event_trigger: ddl_command_end CREATE PROPERTY GRAPH +DROP PROPERTY GRAPH gx; +NOTICE: test_event_trigger: ddl_command_end DROP PROPERTY GRAPH +DROP TABLE t1x, t2x; +NOTICE: test_event_trigger: ddl_command_end DROP TABLE -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; ERROR: permission denied to change owner of event trigger "regress_event_trigger" diff --git a/src/test/regress/expected/object_address.out b/src/test/regress/expected/object_address.out index 97227d67a54..729c3537f25 100644 --- a/src/test/regress/expected/object_address.out +++ b/src/test/regress/expected/object_address.out @@ -593,7 +593,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace @@ -653,6 +655,8 @@ ORDER BY objects.classid, objects.objid, objects.objsubid; ("(""parameter ACL"",,,)")|("(""parameter ACL"",,)")|NULL ("(""property graph element"",,,)")|("(""property graph element"",,)")|NULL ("(""property graph label"",,,)")|("(""property graph label"",,)")|NULL +("(""property graph element label"",,,)")|("(""property graph element label"",,)")|NULL ("(""property graph property"",,,)")|("(""property graph property"",,)")|NULL +("(""property graph label property"",,,)")|("(""property graph label property"",,)")|NULL -- restore normal output mode \a\t diff --git a/src/test/regress/sql/event_trigger.sql b/src/test/regress/sql/event_trigger.sql index 32e9bb58c5e..271f443378b 100644 --- a/src/test/regress/sql/event_trigger.sql +++ b/src/test/regress/sql/event_trigger.sql @@ -143,6 +143,19 @@ create user mapping for regress_evt_user server useless_server; alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +CREATE TABLE t2x (i int PRIMARY KEY, j text); + +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); + +DROP PROPERTY GRAPH gx; +DROP TABLE t1x, t2x; + -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; diff --git a/src/test/regress/sql/object_address.sql b/src/test/regress/sql/object_address.sql index 1bbe9457c1c..620dacf1045 100644 --- a/src/test/regress/sql/object_address.sql +++ b/src/test/regress/sql/object_address.sql @@ -282,7 +282,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace -- 2.34.1 --gtUR827Uq8d5gVsQ-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v3] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-23 09:27 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-23 09:27 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing them to hit the default case and error out with "unsupported object class". During DROP PROPERTY GRAPH, this manifests when an event trigger is active, because pg_event_trigger_ddl_commands() calls these functions. The same code paths are also reachable via pg_identify_object() and pg_identify_object_as_address(). This commit adds the missing cases. Test coverage is added in object_address.sql for these two catalog types and in create_property_graph.sql covering all property graph object types. A test in event_trigger.sql verifies that DROP PROPERTY GRAPH works correctly when an event trigger is active. Author: Bertrand Drouvot <[email protected]> Reviewed-by: Michael Paquier <[email protected]> Reviewed-by: Ashutosh Bapat <[email protected]> Discussion: https://postgr.es/m/aej1DkLwhyZWmtxJ@bdtpg --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 78 ++++++++++++++++ src/test/regress/expected/event_trigger.out | 17 ++++ src/test/regress/expected/object_address.out | 10 +- .../regress/sql/create_property_graph.sql | 23 +++++ src/test/regress/sql/event_trigger.sql | 13 +++ src/test/regress/sql/object_address.sql | 6 +- 7 files changed, 238 insertions(+), 2 deletions(-) 14.7% src/backend/catalog/ 75.5% src/test/regress/expected/ 9.7% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..eb9e17fb727 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -752,6 +752,84 @@ SELECT (pg_identify_object(classid, objid, objsubid)).* type | create_property_graph_tests | g2 | create_property_graph_tests.g2 (21 rows) +-- test object address functions with recursive dependency walk +-- covers all property graph object types including indirect dependents +SELECT * +FROM ( + WITH RECURSIVE deps (classid, objid, objsubid, refclassid, refobjid, refobjsubid) AS ( + SELECT classid, objid, objsubid, + refclassid, refobjid, refobjsubid + FROM pg_depend + WHERE refclassid = 'pg_class'::regclass AND + refobjid = 'create_property_graph_tests.gt'::regclass + UNION ALL + SELECT d.classid, d.objid, d.objsubid, + d.refclassid, d.refobjid, d.refobjsubid + FROM pg_depend d + JOIN deps dp ON d.refclassid = dp.classid AND d.refobjid = dp.objid AND d.refobjsubid = dp.objsubid + ) + SELECT pg_describe_object(classid, objid, objsubid) as obj, + pg_identify_object(classid, objid, objsubid) as ident, + pg_identify_object_as_address(classid, objid, objsubid) as addr + FROM deps +) s +ORDER BY obj COLLATE "C", ident::text COLLATE "C"; + obj | ident | addr +----------------------------------------------------------+----------------------------------------------------------------------------+---------------------------------------------------------------------------- + edge e of property graph gt | ("property graph element",,,"e of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,e}",{}) + edge e of property graph gt | ("property graph element",,,"e of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,e}",{}) + edge e of property graph gt | ("property graph element",,,"e of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of property graph gt | ("property graph label",,,"e of create_property_graph_tests.gt") | ("property graph label","{create_property_graph_tests,gt,e}",{}) + label v1 of property graph gt | ("property graph label",,,"v1 of create_property_graph_tests.gt") | ("property graph label","{create_property_graph_tests,gt,v1}",{}) + label v1 of vertex v1 of property graph gt | ("property graph element label",,,"v1 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v1}",{}) + label v1 of vertex v1 of property graph gt | ("property graph element label",,,"v1 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v1}",{}) + label v2 of property graph gt | ("property graph label",,,"v2 of create_property_graph_tests.gt") | ("property graph label","{create_property_graph_tests,gt,v2}",{}) + label v2 of vertex v2 of property graph gt | ("property graph element label",,,"v2 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v2}",{}) + label v2 of vertex v2 of property graph gt | ("property graph element label",,,"v2 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v2}",{}) + property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property a of property graph gt | ("property graph property",,,"a of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,a}",{}) + property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property b of property graph gt | ("property graph property",,,"b of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,b}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of property graph gt | ("property graph property",,,"c of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,c}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of property graph gt | ("property graph property",,,"k1 of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,k1}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of property graph gt | ("property graph property",,,"k2 of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,k2}",{}) + property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property m of property graph gt | ("property graph property",,,"m of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,m}",{}) + property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property n of property graph gt | ("property graph property",,,"n of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,n}",{}) + type gt | (type,create_property_graph_tests,gt,create_property_graph_tests.gt) | (type,{create_property_graph_tests.gt},{}) + type gt[] | (type,create_property_graph_tests,_gt,create_property_graph_tests.gt[]) | (type,{create_property_graph_tests.gt[]},{}) + vertex v1 of property graph gt | ("property graph element",,,"v1 of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,v1}",{}) + vertex v2 of property graph gt | ("property graph element",,,"v2 of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,v2}",{}) +(52 rows) + \a\t SELECT pg_get_propgraphdef('g2'::regclass); CREATE PROPERTY GRAPH create_property_graph_tests.g2 diff --git a/src/test/regress/expected/event_trigger.out b/src/test/regress/expected/event_trigger.out index 065f586310f..ed8d5df397e 100644 --- a/src/test/regress/expected/event_trigger.out +++ b/src/test/regress/expected/event_trigger.out @@ -173,6 +173,23 @@ NOTICE: test_event_trigger: ddl_command_end CREATE USER MAPPING alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; NOTICE: test_event_trigger: ddl_command_end ALTER DEFAULT PRIVILEGES +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE TABLE t2x (i int PRIMARY KEY, j text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); +NOTICE: test_event_trigger: ddl_command_end CREATE PROPERTY GRAPH +DROP PROPERTY GRAPH gx; +NOTICE: test_event_trigger: ddl_command_end DROP PROPERTY GRAPH +DROP TABLE t1x, t2x; +NOTICE: test_event_trigger: ddl_command_end DROP TABLE -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; ERROR: permission denied to change owner of event trigger "regress_event_trigger" diff --git a/src/test/regress/expected/object_address.out b/src/test/regress/expected/object_address.out index 97227d67a54..5e53f0b092e 100644 --- a/src/test/regress/expected/object_address.out +++ b/src/test/regress/expected/object_address.out @@ -67,7 +67,9 @@ DECLARE BEGIN FOR objtype IN VALUES ('toast table'), ('index column'), ('sequence column'), ('toast table column'), ('view column'), ('materialized view column'), - ('property graph element'), ('property graph label'), ('property graph property') + ('property graph element'), ('property graph element label'), + ('property graph label'), ('property graph label property'), + ('property graph property') LOOP BEGIN PERFORM pg_get_object_address(objtype, '{one}', '{}'); @@ -84,7 +86,9 @@ WARNING: error for toast table column: unsupported object type "toast table col WARNING: error for view column: unsupported object type "view column" WARNING: error for materialized view column: unsupported object type "materialized view column" WARNING: error for property graph element: unsupported object type "property graph element" +WARNING: error for property graph element label: unrecognized object type "property graph element label" WARNING: error for property graph label: unsupported object type "property graph label" +WARNING: error for property graph label property: unrecognized object type "property graph label property" WARNING: error for property graph property: unsupported object type "property graph property" -- miscellaneous other errors select * from pg_get_object_address('operator of access method', '{btree,integer_ops,1}', '{int4,bool}'); @@ -593,7 +597,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace @@ -653,6 +659,8 @@ ORDER BY objects.classid, objects.objid, objects.objsubid; ("(""parameter ACL"",,,)")|("(""parameter ACL"",,)")|NULL ("(""property graph element"",,,)")|("(""property graph element"",,)")|NULL ("(""property graph label"",,,)")|("(""property graph label"",,)")|NULL +("(""property graph element label"",,,)")|("(""property graph element label"",,)")|NULL ("(""property graph property"",,,)")|("(""property graph property"",,)")|NULL +("(""property graph label property"",,,)")|("(""property graph label property"",,)")|NULL -- restore normal output mode \a\t diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..9608dd5c4af 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -298,6 +298,29 @@ SELECT (pg_identify_object(classid, objid, objsubid)).* refobjid = 'create_property_graph_tests.g2'::regclass ORDER BY 1, 2, 3, 4; +-- test object address functions with recursive dependency walk +-- covers all property graph object types including indirect dependents +SELECT * +FROM ( + WITH RECURSIVE deps (classid, objid, objsubid, refclassid, refobjid, refobjsubid) AS ( + SELECT classid, objid, objsubid, + refclassid, refobjid, refobjsubid + FROM pg_depend + WHERE refclassid = 'pg_class'::regclass AND + refobjid = 'create_property_graph_tests.gt'::regclass + UNION ALL + SELECT d.classid, d.objid, d.objsubid, + d.refclassid, d.refobjid, d.refobjsubid + FROM pg_depend d + JOIN deps dp ON d.refclassid = dp.classid AND d.refobjid = dp.objid AND d.refobjsubid = dp.objsubid + ) + SELECT pg_describe_object(classid, objid, objsubid) as obj, + pg_identify_object(classid, objid, objsubid) as ident, + pg_identify_object_as_address(classid, objid, objsubid) as addr + FROM deps +) s +ORDER BY obj COLLATE "C", ident::text COLLATE "C"; + \a\t SELECT pg_get_propgraphdef('g2'::regclass); SELECT pg_get_propgraphdef('g3'::regclass); diff --git a/src/test/regress/sql/event_trigger.sql b/src/test/regress/sql/event_trigger.sql index 32e9bb58c5e..271f443378b 100644 --- a/src/test/regress/sql/event_trigger.sql +++ b/src/test/regress/sql/event_trigger.sql @@ -143,6 +143,19 @@ create user mapping for regress_evt_user server useless_server; alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +CREATE TABLE t2x (i int PRIMARY KEY, j text); + +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); + +DROP PROPERTY GRAPH gx; +DROP TABLE t1x, t2x; + -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; diff --git a/src/test/regress/sql/object_address.sql b/src/test/regress/sql/object_address.sql index 1bbe9457c1c..27109d421c7 100644 --- a/src/test/regress/sql/object_address.sql +++ b/src/test/regress/sql/object_address.sql @@ -67,7 +67,9 @@ DECLARE BEGIN FOR objtype IN VALUES ('toast table'), ('index column'), ('sequence column'), ('toast table column'), ('view column'), ('materialized view column'), - ('property graph element'), ('property graph label'), ('property graph property') + ('property graph element'), ('property graph element label'), + ('property graph label'), ('property graph label property'), + ('property graph property') LOOP BEGIN PERFORM pg_get_object_address(objtype, '{one}', '{}'); @@ -282,7 +284,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace -- 2.34.1 --R84XrR4Hgw0dH3Ec-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v3] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-23 09:27 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-23 09:27 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing them to hit the default case and error out with "unsupported object class". During DROP PROPERTY GRAPH, this manifests when an event trigger is active, because pg_event_trigger_ddl_commands() calls these functions. The same code paths are also reachable via pg_identify_object() and pg_identify_object_as_address(). This commit adds the missing cases. Test coverage is added in object_address.sql for these two catalog types and in create_property_graph.sql covering all property graph object types. A test in event_trigger.sql verifies that DROP PROPERTY GRAPH works correctly when an event trigger is active. Author: Bertrand Drouvot <[email protected]> Reviewed-by: Michael Paquier <[email protected]> Reviewed-by: Ashutosh Bapat <[email protected]> Discussion: https://postgr.es/m/aej1DkLwhyZWmtxJ@bdtpg --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 78 ++++++++++++++++ src/test/regress/expected/event_trigger.out | 17 ++++ src/test/regress/expected/object_address.out | 10 +- .../regress/sql/create_property_graph.sql | 23 +++++ src/test/regress/sql/event_trigger.sql | 13 +++ src/test/regress/sql/object_address.sql | 6 +- 7 files changed, 238 insertions(+), 2 deletions(-) 14.7% src/backend/catalog/ 75.5% src/test/regress/expected/ 9.7% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..eb9e17fb727 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -752,6 +752,84 @@ SELECT (pg_identify_object(classid, objid, objsubid)).* type | create_property_graph_tests | g2 | create_property_graph_tests.g2 (21 rows) +-- test object address functions with recursive dependency walk +-- covers all property graph object types including indirect dependents +SELECT * +FROM ( + WITH RECURSIVE deps (classid, objid, objsubid, refclassid, refobjid, refobjsubid) AS ( + SELECT classid, objid, objsubid, + refclassid, refobjid, refobjsubid + FROM pg_depend + WHERE refclassid = 'pg_class'::regclass AND + refobjid = 'create_property_graph_tests.gt'::regclass + UNION ALL + SELECT d.classid, d.objid, d.objsubid, + d.refclassid, d.refobjid, d.refobjsubid + FROM pg_depend d + JOIN deps dp ON d.refclassid = dp.classid AND d.refobjid = dp.objid AND d.refobjsubid = dp.objsubid + ) + SELECT pg_describe_object(classid, objid, objsubid) as obj, + pg_identify_object(classid, objid, objsubid) as ident, + pg_identify_object_as_address(classid, objid, objsubid) as addr + FROM deps +) s +ORDER BY obj COLLATE "C", ident::text COLLATE "C"; + obj | ident | addr +----------------------------------------------------------+----------------------------------------------------------------------------+---------------------------------------------------------------------------- + edge e of property graph gt | ("property graph element",,,"e of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,e}",{}) + edge e of property graph gt | ("property graph element",,,"e of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,e}",{}) + edge e of property graph gt | ("property graph element",,,"e of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of property graph gt | ("property graph label",,,"e of create_property_graph_tests.gt") | ("property graph label","{create_property_graph_tests,gt,e}",{}) + label v1 of property graph gt | ("property graph label",,,"v1 of create_property_graph_tests.gt") | ("property graph label","{create_property_graph_tests,gt,v1}",{}) + label v1 of vertex v1 of property graph gt | ("property graph element label",,,"v1 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v1}",{}) + label v1 of vertex v1 of property graph gt | ("property graph element label",,,"v1 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v1}",{}) + label v2 of property graph gt | ("property graph label",,,"v2 of create_property_graph_tests.gt") | ("property graph label","{create_property_graph_tests,gt,v2}",{}) + label v2 of vertex v2 of property graph gt | ("property graph element label",,,"v2 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v2}",{}) + label v2 of vertex v2 of property graph gt | ("property graph element label",,,"v2 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v2}",{}) + property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property a of property graph gt | ("property graph property",,,"a of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,a}",{}) + property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property b of property graph gt | ("property graph property",,,"b of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,b}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of property graph gt | ("property graph property",,,"c of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,c}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of property graph gt | ("property graph property",,,"k1 of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,k1}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of property graph gt | ("property graph property",,,"k2 of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,k2}",{}) + property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property m of property graph gt | ("property graph property",,,"m of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,m}",{}) + property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property n of property graph gt | ("property graph property",,,"n of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,n}",{}) + type gt | (type,create_property_graph_tests,gt,create_property_graph_tests.gt) | (type,{create_property_graph_tests.gt},{}) + type gt[] | (type,create_property_graph_tests,_gt,create_property_graph_tests.gt[]) | (type,{create_property_graph_tests.gt[]},{}) + vertex v1 of property graph gt | ("property graph element",,,"v1 of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,v1}",{}) + vertex v2 of property graph gt | ("property graph element",,,"v2 of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,v2}",{}) +(52 rows) + \a\t SELECT pg_get_propgraphdef('g2'::regclass); CREATE PROPERTY GRAPH create_property_graph_tests.g2 diff --git a/src/test/regress/expected/event_trigger.out b/src/test/regress/expected/event_trigger.out index 065f586310f..ed8d5df397e 100644 --- a/src/test/regress/expected/event_trigger.out +++ b/src/test/regress/expected/event_trigger.out @@ -173,6 +173,23 @@ NOTICE: test_event_trigger: ddl_command_end CREATE USER MAPPING alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; NOTICE: test_event_trigger: ddl_command_end ALTER DEFAULT PRIVILEGES +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE TABLE t2x (i int PRIMARY KEY, j text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); +NOTICE: test_event_trigger: ddl_command_end CREATE PROPERTY GRAPH +DROP PROPERTY GRAPH gx; +NOTICE: test_event_trigger: ddl_command_end DROP PROPERTY GRAPH +DROP TABLE t1x, t2x; +NOTICE: test_event_trigger: ddl_command_end DROP TABLE -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; ERROR: permission denied to change owner of event trigger "regress_event_trigger" diff --git a/src/test/regress/expected/object_address.out b/src/test/regress/expected/object_address.out index 97227d67a54..5e53f0b092e 100644 --- a/src/test/regress/expected/object_address.out +++ b/src/test/regress/expected/object_address.out @@ -67,7 +67,9 @@ DECLARE BEGIN FOR objtype IN VALUES ('toast table'), ('index column'), ('sequence column'), ('toast table column'), ('view column'), ('materialized view column'), - ('property graph element'), ('property graph label'), ('property graph property') + ('property graph element'), ('property graph element label'), + ('property graph label'), ('property graph label property'), + ('property graph property') LOOP BEGIN PERFORM pg_get_object_address(objtype, '{one}', '{}'); @@ -84,7 +86,9 @@ WARNING: error for toast table column: unsupported object type "toast table col WARNING: error for view column: unsupported object type "view column" WARNING: error for materialized view column: unsupported object type "materialized view column" WARNING: error for property graph element: unsupported object type "property graph element" +WARNING: error for property graph element label: unrecognized object type "property graph element label" WARNING: error for property graph label: unsupported object type "property graph label" +WARNING: error for property graph label property: unrecognized object type "property graph label property" WARNING: error for property graph property: unsupported object type "property graph property" -- miscellaneous other errors select * from pg_get_object_address('operator of access method', '{btree,integer_ops,1}', '{int4,bool}'); @@ -593,7 +597,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace @@ -653,6 +659,8 @@ ORDER BY objects.classid, objects.objid, objects.objsubid; ("(""parameter ACL"",,,)")|("(""parameter ACL"",,)")|NULL ("(""property graph element"",,,)")|("(""property graph element"",,)")|NULL ("(""property graph label"",,,)")|("(""property graph label"",,)")|NULL +("(""property graph element label"",,,)")|("(""property graph element label"",,)")|NULL ("(""property graph property"",,,)")|("(""property graph property"",,)")|NULL +("(""property graph label property"",,,)")|("(""property graph label property"",,)")|NULL -- restore normal output mode \a\t diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..9608dd5c4af 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -298,6 +298,29 @@ SELECT (pg_identify_object(classid, objid, objsubid)).* refobjid = 'create_property_graph_tests.g2'::regclass ORDER BY 1, 2, 3, 4; +-- test object address functions with recursive dependency walk +-- covers all property graph object types including indirect dependents +SELECT * +FROM ( + WITH RECURSIVE deps (classid, objid, objsubid, refclassid, refobjid, refobjsubid) AS ( + SELECT classid, objid, objsubid, + refclassid, refobjid, refobjsubid + FROM pg_depend + WHERE refclassid = 'pg_class'::regclass AND + refobjid = 'create_property_graph_tests.gt'::regclass + UNION ALL + SELECT d.classid, d.objid, d.objsubid, + d.refclassid, d.refobjid, d.refobjsubid + FROM pg_depend d + JOIN deps dp ON d.refclassid = dp.classid AND d.refobjid = dp.objid AND d.refobjsubid = dp.objsubid + ) + SELECT pg_describe_object(classid, objid, objsubid) as obj, + pg_identify_object(classid, objid, objsubid) as ident, + pg_identify_object_as_address(classid, objid, objsubid) as addr + FROM deps +) s +ORDER BY obj COLLATE "C", ident::text COLLATE "C"; + \a\t SELECT pg_get_propgraphdef('g2'::regclass); SELECT pg_get_propgraphdef('g3'::regclass); diff --git a/src/test/regress/sql/event_trigger.sql b/src/test/regress/sql/event_trigger.sql index 32e9bb58c5e..271f443378b 100644 --- a/src/test/regress/sql/event_trigger.sql +++ b/src/test/regress/sql/event_trigger.sql @@ -143,6 +143,19 @@ create user mapping for regress_evt_user server useless_server; alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +CREATE TABLE t2x (i int PRIMARY KEY, j text); + +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); + +DROP PROPERTY GRAPH gx; +DROP TABLE t1x, t2x; + -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; diff --git a/src/test/regress/sql/object_address.sql b/src/test/regress/sql/object_address.sql index 1bbe9457c1c..27109d421c7 100644 --- a/src/test/regress/sql/object_address.sql +++ b/src/test/regress/sql/object_address.sql @@ -67,7 +67,9 @@ DECLARE BEGIN FOR objtype IN VALUES ('toast table'), ('index column'), ('sequence column'), ('toast table column'), ('view column'), ('materialized view column'), - ('property graph element'), ('property graph label'), ('property graph property') + ('property graph element'), ('property graph element label'), + ('property graph label'), ('property graph label property'), + ('property graph property') LOOP BEGIN PERFORM pg_get_object_address(objtype, '{one}', '{}'); @@ -282,7 +284,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace -- 2.34.1 --R84XrR4Hgw0dH3Ec-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v3] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-23 09:27 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-23 09:27 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing them to hit the default case and error out with "unsupported object class". During DROP PROPERTY GRAPH, this manifests when an event trigger is active, because pg_event_trigger_ddl_commands() calls these functions. The same code paths are also reachable via pg_identify_object() and pg_identify_object_as_address(). This commit adds the missing cases. Test coverage is added in object_address.sql for these two catalog types and in create_property_graph.sql covering all property graph object types. A test in event_trigger.sql verifies that DROP PROPERTY GRAPH works correctly when an event trigger is active. Author: Bertrand Drouvot <[email protected]> Reviewed-by: Michael Paquier <[email protected]> Reviewed-by: Ashutosh Bapat <[email protected]> Discussion: https://postgr.es/m/aej1DkLwhyZWmtxJ@bdtpg --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 78 ++++++++++++++++ src/test/regress/expected/event_trigger.out | 17 ++++ src/test/regress/expected/object_address.out | 10 +- .../regress/sql/create_property_graph.sql | 23 +++++ src/test/regress/sql/event_trigger.sql | 13 +++ src/test/regress/sql/object_address.sql | 6 +- 7 files changed, 238 insertions(+), 2 deletions(-) 14.7% src/backend/catalog/ 75.5% src/test/regress/expected/ 9.7% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..eb9e17fb727 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -752,6 +752,84 @@ SELECT (pg_identify_object(classid, objid, objsubid)).* type | create_property_graph_tests | g2 | create_property_graph_tests.g2 (21 rows) +-- test object address functions with recursive dependency walk +-- covers all property graph object types including indirect dependents +SELECT * +FROM ( + WITH RECURSIVE deps (classid, objid, objsubid, refclassid, refobjid, refobjsubid) AS ( + SELECT classid, objid, objsubid, + refclassid, refobjid, refobjsubid + FROM pg_depend + WHERE refclassid = 'pg_class'::regclass AND + refobjid = 'create_property_graph_tests.gt'::regclass + UNION ALL + SELECT d.classid, d.objid, d.objsubid, + d.refclassid, d.refobjid, d.refobjsubid + FROM pg_depend d + JOIN deps dp ON d.refclassid = dp.classid AND d.refobjid = dp.objid AND d.refobjsubid = dp.objsubid + ) + SELECT pg_describe_object(classid, objid, objsubid) as obj, + pg_identify_object(classid, objid, objsubid) as ident, + pg_identify_object_as_address(classid, objid, objsubid) as addr + FROM deps +) s +ORDER BY obj COLLATE "C", ident::text COLLATE "C"; + obj | ident | addr +----------------------------------------------------------+----------------------------------------------------------------------------+---------------------------------------------------------------------------- + edge e of property graph gt | ("property graph element",,,"e of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,e}",{}) + edge e of property graph gt | ("property graph element",,,"e of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,e}",{}) + edge e of property graph gt | ("property graph element",,,"e of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of property graph gt | ("property graph label",,,"e of create_property_graph_tests.gt") | ("property graph label","{create_property_graph_tests,gt,e}",{}) + label v1 of property graph gt | ("property graph label",,,"v1 of create_property_graph_tests.gt") | ("property graph label","{create_property_graph_tests,gt,v1}",{}) + label v1 of vertex v1 of property graph gt | ("property graph element label",,,"v1 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v1}",{}) + label v1 of vertex v1 of property graph gt | ("property graph element label",,,"v1 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v1}",{}) + label v2 of property graph gt | ("property graph label",,,"v2 of create_property_graph_tests.gt") | ("property graph label","{create_property_graph_tests,gt,v2}",{}) + label v2 of vertex v2 of property graph gt | ("property graph element label",,,"v2 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v2}",{}) + label v2 of vertex v2 of property graph gt | ("property graph element label",,,"v2 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v2}",{}) + property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property a of property graph gt | ("property graph property",,,"a of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,a}",{}) + property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property b of property graph gt | ("property graph property",,,"b of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,b}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of property graph gt | ("property graph property",,,"c of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,c}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of property graph gt | ("property graph property",,,"k1 of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,k1}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of property graph gt | ("property graph property",,,"k2 of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,k2}",{}) + property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property m of property graph gt | ("property graph property",,,"m of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,m}",{}) + property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property n of property graph gt | ("property graph property",,,"n of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,n}",{}) + type gt | (type,create_property_graph_tests,gt,create_property_graph_tests.gt) | (type,{create_property_graph_tests.gt},{}) + type gt[] | (type,create_property_graph_tests,_gt,create_property_graph_tests.gt[]) | (type,{create_property_graph_tests.gt[]},{}) + vertex v1 of property graph gt | ("property graph element",,,"v1 of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,v1}",{}) + vertex v2 of property graph gt | ("property graph element",,,"v2 of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,v2}",{}) +(52 rows) + \a\t SELECT pg_get_propgraphdef('g2'::regclass); CREATE PROPERTY GRAPH create_property_graph_tests.g2 diff --git a/src/test/regress/expected/event_trigger.out b/src/test/regress/expected/event_trigger.out index 065f586310f..ed8d5df397e 100644 --- a/src/test/regress/expected/event_trigger.out +++ b/src/test/regress/expected/event_trigger.out @@ -173,6 +173,23 @@ NOTICE: test_event_trigger: ddl_command_end CREATE USER MAPPING alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; NOTICE: test_event_trigger: ddl_command_end ALTER DEFAULT PRIVILEGES +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE TABLE t2x (i int PRIMARY KEY, j text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); +NOTICE: test_event_trigger: ddl_command_end CREATE PROPERTY GRAPH +DROP PROPERTY GRAPH gx; +NOTICE: test_event_trigger: ddl_command_end DROP PROPERTY GRAPH +DROP TABLE t1x, t2x; +NOTICE: test_event_trigger: ddl_command_end DROP TABLE -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; ERROR: permission denied to change owner of event trigger "regress_event_trigger" diff --git a/src/test/regress/expected/object_address.out b/src/test/regress/expected/object_address.out index 97227d67a54..5e53f0b092e 100644 --- a/src/test/regress/expected/object_address.out +++ b/src/test/regress/expected/object_address.out @@ -67,7 +67,9 @@ DECLARE BEGIN FOR objtype IN VALUES ('toast table'), ('index column'), ('sequence column'), ('toast table column'), ('view column'), ('materialized view column'), - ('property graph element'), ('property graph label'), ('property graph property') + ('property graph element'), ('property graph element label'), + ('property graph label'), ('property graph label property'), + ('property graph property') LOOP BEGIN PERFORM pg_get_object_address(objtype, '{one}', '{}'); @@ -84,7 +86,9 @@ WARNING: error for toast table column: unsupported object type "toast table col WARNING: error for view column: unsupported object type "view column" WARNING: error for materialized view column: unsupported object type "materialized view column" WARNING: error for property graph element: unsupported object type "property graph element" +WARNING: error for property graph element label: unrecognized object type "property graph element label" WARNING: error for property graph label: unsupported object type "property graph label" +WARNING: error for property graph label property: unrecognized object type "property graph label property" WARNING: error for property graph property: unsupported object type "property graph property" -- miscellaneous other errors select * from pg_get_object_address('operator of access method', '{btree,integer_ops,1}', '{int4,bool}'); @@ -593,7 +597,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace @@ -653,6 +659,8 @@ ORDER BY objects.classid, objects.objid, objects.objsubid; ("(""parameter ACL"",,,)")|("(""parameter ACL"",,)")|NULL ("(""property graph element"",,,)")|("(""property graph element"",,)")|NULL ("(""property graph label"",,,)")|("(""property graph label"",,)")|NULL +("(""property graph element label"",,,)")|("(""property graph element label"",,)")|NULL ("(""property graph property"",,,)")|("(""property graph property"",,)")|NULL +("(""property graph label property"",,,)")|("(""property graph label property"",,)")|NULL -- restore normal output mode \a\t diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..9608dd5c4af 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -298,6 +298,29 @@ SELECT (pg_identify_object(classid, objid, objsubid)).* refobjid = 'create_property_graph_tests.g2'::regclass ORDER BY 1, 2, 3, 4; +-- test object address functions with recursive dependency walk +-- covers all property graph object types including indirect dependents +SELECT * +FROM ( + WITH RECURSIVE deps (classid, objid, objsubid, refclassid, refobjid, refobjsubid) AS ( + SELECT classid, objid, objsubid, + refclassid, refobjid, refobjsubid + FROM pg_depend + WHERE refclassid = 'pg_class'::regclass AND + refobjid = 'create_property_graph_tests.gt'::regclass + UNION ALL + SELECT d.classid, d.objid, d.objsubid, + d.refclassid, d.refobjid, d.refobjsubid + FROM pg_depend d + JOIN deps dp ON d.refclassid = dp.classid AND d.refobjid = dp.objid AND d.refobjsubid = dp.objsubid + ) + SELECT pg_describe_object(classid, objid, objsubid) as obj, + pg_identify_object(classid, objid, objsubid) as ident, + pg_identify_object_as_address(classid, objid, objsubid) as addr + FROM deps +) s +ORDER BY obj COLLATE "C", ident::text COLLATE "C"; + \a\t SELECT pg_get_propgraphdef('g2'::regclass); SELECT pg_get_propgraphdef('g3'::regclass); diff --git a/src/test/regress/sql/event_trigger.sql b/src/test/regress/sql/event_trigger.sql index 32e9bb58c5e..271f443378b 100644 --- a/src/test/regress/sql/event_trigger.sql +++ b/src/test/regress/sql/event_trigger.sql @@ -143,6 +143,19 @@ create user mapping for regress_evt_user server useless_server; alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +CREATE TABLE t2x (i int PRIMARY KEY, j text); + +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); + +DROP PROPERTY GRAPH gx; +DROP TABLE t1x, t2x; + -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; diff --git a/src/test/regress/sql/object_address.sql b/src/test/regress/sql/object_address.sql index 1bbe9457c1c..27109d421c7 100644 --- a/src/test/regress/sql/object_address.sql +++ b/src/test/regress/sql/object_address.sql @@ -67,7 +67,9 @@ DECLARE BEGIN FOR objtype IN VALUES ('toast table'), ('index column'), ('sequence column'), ('toast table column'), ('view column'), ('materialized view column'), - ('property graph element'), ('property graph label'), ('property graph property') + ('property graph element'), ('property graph element label'), + ('property graph label'), ('property graph label property'), + ('property graph property') LOOP BEGIN PERFORM pg_get_object_address(objtype, '{one}', '{}'); @@ -282,7 +284,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace -- 2.34.1 --R84XrR4Hgw0dH3Ec-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v3] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-23 09:27 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-23 09:27 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing them to hit the default case and error out with "unsupported object class". During DROP PROPERTY GRAPH, this manifests when an event trigger is active, because pg_event_trigger_ddl_commands() calls these functions. The same code paths are also reachable via pg_identify_object() and pg_identify_object_as_address(). This commit adds the missing cases. Test coverage is added in object_address.sql for these two catalog types and in create_property_graph.sql covering all property graph object types. A test in event_trigger.sql verifies that DROP PROPERTY GRAPH works correctly when an event trigger is active. Author: Bertrand Drouvot <[email protected]> Reviewed-by: Michael Paquier <[email protected]> Reviewed-by: Ashutosh Bapat <[email protected]> Discussion: https://postgr.es/m/aej1DkLwhyZWmtxJ@bdtpg --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 78 ++++++++++++++++ src/test/regress/expected/event_trigger.out | 17 ++++ src/test/regress/expected/object_address.out | 10 +- .../regress/sql/create_property_graph.sql | 23 +++++ src/test/regress/sql/event_trigger.sql | 13 +++ src/test/regress/sql/object_address.sql | 6 +- 7 files changed, 238 insertions(+), 2 deletions(-) 14.7% src/backend/catalog/ 75.5% src/test/regress/expected/ 9.7% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..eb9e17fb727 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -752,6 +752,84 @@ SELECT (pg_identify_object(classid, objid, objsubid)).* type | create_property_graph_tests | g2 | create_property_graph_tests.g2 (21 rows) +-- test object address functions with recursive dependency walk +-- covers all property graph object types including indirect dependents +SELECT * +FROM ( + WITH RECURSIVE deps (classid, objid, objsubid, refclassid, refobjid, refobjsubid) AS ( + SELECT classid, objid, objsubid, + refclassid, refobjid, refobjsubid + FROM pg_depend + WHERE refclassid = 'pg_class'::regclass AND + refobjid = 'create_property_graph_tests.gt'::regclass + UNION ALL + SELECT d.classid, d.objid, d.objsubid, + d.refclassid, d.refobjid, d.refobjsubid + FROM pg_depend d + JOIN deps dp ON d.refclassid = dp.classid AND d.refobjid = dp.objid AND d.refobjsubid = dp.objsubid + ) + SELECT pg_describe_object(classid, objid, objsubid) as obj, + pg_identify_object(classid, objid, objsubid) as ident, + pg_identify_object_as_address(classid, objid, objsubid) as addr + FROM deps +) s +ORDER BY obj COLLATE "C", ident::text COLLATE "C"; + obj | ident | addr +----------------------------------------------------------+----------------------------------------------------------------------------+---------------------------------------------------------------------------- + edge e of property graph gt | ("property graph element",,,"e of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,e}",{}) + edge e of property graph gt | ("property graph element",,,"e of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,e}",{}) + edge e of property graph gt | ("property graph element",,,"e of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of property graph gt | ("property graph label",,,"e of create_property_graph_tests.gt") | ("property graph label","{create_property_graph_tests,gt,e}",{}) + label v1 of property graph gt | ("property graph label",,,"v1 of create_property_graph_tests.gt") | ("property graph label","{create_property_graph_tests,gt,v1}",{}) + label v1 of vertex v1 of property graph gt | ("property graph element label",,,"v1 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v1}",{}) + label v1 of vertex v1 of property graph gt | ("property graph element label",,,"v1 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v1}",{}) + label v2 of property graph gt | ("property graph label",,,"v2 of create_property_graph_tests.gt") | ("property graph label","{create_property_graph_tests,gt,v2}",{}) + label v2 of vertex v2 of property graph gt | ("property graph element label",,,"v2 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v2}",{}) + label v2 of vertex v2 of property graph gt | ("property graph element label",,,"v2 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v2}",{}) + property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property a of property graph gt | ("property graph property",,,"a of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,a}",{}) + property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property b of property graph gt | ("property graph property",,,"b of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,b}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of property graph gt | ("property graph property",,,"c of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,c}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of property graph gt | ("property graph property",,,"k1 of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,k1}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of property graph gt | ("property graph property",,,"k2 of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,k2}",{}) + property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property m of property graph gt | ("property graph property",,,"m of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,m}",{}) + property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property n of property graph gt | ("property graph property",,,"n of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,n}",{}) + type gt | (type,create_property_graph_tests,gt,create_property_graph_tests.gt) | (type,{create_property_graph_tests.gt},{}) + type gt[] | (type,create_property_graph_tests,_gt,create_property_graph_tests.gt[]) | (type,{create_property_graph_tests.gt[]},{}) + vertex v1 of property graph gt | ("property graph element",,,"v1 of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,v1}",{}) + vertex v2 of property graph gt | ("property graph element",,,"v2 of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,v2}",{}) +(52 rows) + \a\t SELECT pg_get_propgraphdef('g2'::regclass); CREATE PROPERTY GRAPH create_property_graph_tests.g2 diff --git a/src/test/regress/expected/event_trigger.out b/src/test/regress/expected/event_trigger.out index 065f586310f..ed8d5df397e 100644 --- a/src/test/regress/expected/event_trigger.out +++ b/src/test/regress/expected/event_trigger.out @@ -173,6 +173,23 @@ NOTICE: test_event_trigger: ddl_command_end CREATE USER MAPPING alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; NOTICE: test_event_trigger: ddl_command_end ALTER DEFAULT PRIVILEGES +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE TABLE t2x (i int PRIMARY KEY, j text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); +NOTICE: test_event_trigger: ddl_command_end CREATE PROPERTY GRAPH +DROP PROPERTY GRAPH gx; +NOTICE: test_event_trigger: ddl_command_end DROP PROPERTY GRAPH +DROP TABLE t1x, t2x; +NOTICE: test_event_trigger: ddl_command_end DROP TABLE -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; ERROR: permission denied to change owner of event trigger "regress_event_trigger" diff --git a/src/test/regress/expected/object_address.out b/src/test/regress/expected/object_address.out index 97227d67a54..5e53f0b092e 100644 --- a/src/test/regress/expected/object_address.out +++ b/src/test/regress/expected/object_address.out @@ -67,7 +67,9 @@ DECLARE BEGIN FOR objtype IN VALUES ('toast table'), ('index column'), ('sequence column'), ('toast table column'), ('view column'), ('materialized view column'), - ('property graph element'), ('property graph label'), ('property graph property') + ('property graph element'), ('property graph element label'), + ('property graph label'), ('property graph label property'), + ('property graph property') LOOP BEGIN PERFORM pg_get_object_address(objtype, '{one}', '{}'); @@ -84,7 +86,9 @@ WARNING: error for toast table column: unsupported object type "toast table col WARNING: error for view column: unsupported object type "view column" WARNING: error for materialized view column: unsupported object type "materialized view column" WARNING: error for property graph element: unsupported object type "property graph element" +WARNING: error for property graph element label: unrecognized object type "property graph element label" WARNING: error for property graph label: unsupported object type "property graph label" +WARNING: error for property graph label property: unrecognized object type "property graph label property" WARNING: error for property graph property: unsupported object type "property graph property" -- miscellaneous other errors select * from pg_get_object_address('operator of access method', '{btree,integer_ops,1}', '{int4,bool}'); @@ -593,7 +597,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace @@ -653,6 +659,8 @@ ORDER BY objects.classid, objects.objid, objects.objsubid; ("(""parameter ACL"",,,)")|("(""parameter ACL"",,)")|NULL ("(""property graph element"",,,)")|("(""property graph element"",,)")|NULL ("(""property graph label"",,,)")|("(""property graph label"",,)")|NULL +("(""property graph element label"",,,)")|("(""property graph element label"",,)")|NULL ("(""property graph property"",,,)")|("(""property graph property"",,)")|NULL +("(""property graph label property"",,,)")|("(""property graph label property"",,)")|NULL -- restore normal output mode \a\t diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..9608dd5c4af 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -298,6 +298,29 @@ SELECT (pg_identify_object(classid, objid, objsubid)).* refobjid = 'create_property_graph_tests.g2'::regclass ORDER BY 1, 2, 3, 4; +-- test object address functions with recursive dependency walk +-- covers all property graph object types including indirect dependents +SELECT * +FROM ( + WITH RECURSIVE deps (classid, objid, objsubid, refclassid, refobjid, refobjsubid) AS ( + SELECT classid, objid, objsubid, + refclassid, refobjid, refobjsubid + FROM pg_depend + WHERE refclassid = 'pg_class'::regclass AND + refobjid = 'create_property_graph_tests.gt'::regclass + UNION ALL + SELECT d.classid, d.objid, d.objsubid, + d.refclassid, d.refobjid, d.refobjsubid + FROM pg_depend d + JOIN deps dp ON d.refclassid = dp.classid AND d.refobjid = dp.objid AND d.refobjsubid = dp.objsubid + ) + SELECT pg_describe_object(classid, objid, objsubid) as obj, + pg_identify_object(classid, objid, objsubid) as ident, + pg_identify_object_as_address(classid, objid, objsubid) as addr + FROM deps +) s +ORDER BY obj COLLATE "C", ident::text COLLATE "C"; + \a\t SELECT pg_get_propgraphdef('g2'::regclass); SELECT pg_get_propgraphdef('g3'::regclass); diff --git a/src/test/regress/sql/event_trigger.sql b/src/test/regress/sql/event_trigger.sql index 32e9bb58c5e..271f443378b 100644 --- a/src/test/regress/sql/event_trigger.sql +++ b/src/test/regress/sql/event_trigger.sql @@ -143,6 +143,19 @@ create user mapping for regress_evt_user server useless_server; alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +CREATE TABLE t2x (i int PRIMARY KEY, j text); + +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); + +DROP PROPERTY GRAPH gx; +DROP TABLE t1x, t2x; + -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; diff --git a/src/test/regress/sql/object_address.sql b/src/test/regress/sql/object_address.sql index 1bbe9457c1c..27109d421c7 100644 --- a/src/test/regress/sql/object_address.sql +++ b/src/test/regress/sql/object_address.sql @@ -67,7 +67,9 @@ DECLARE BEGIN FOR objtype IN VALUES ('toast table'), ('index column'), ('sequence column'), ('toast table column'), ('view column'), ('materialized view column'), - ('property graph element'), ('property graph label'), ('property graph property') + ('property graph element'), ('property graph element label'), + ('property graph label'), ('property graph label property'), + ('property graph property') LOOP BEGIN PERFORM pg_get_object_address(objtype, '{one}', '{}'); @@ -282,7 +284,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace -- 2.34.1 --R84XrR4Hgw0dH3Ec-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v2] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-23 09:27 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-23 09:27 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing them to hit the default case and error out with "unsupported object class". During DROP PROPERTY GRAPH, this manifests when an event trigger is active, because pg_event_trigger_ddl_commands() calls these functions. The same code paths are also reachable via pg_identify_object() and pg_identify_object_as_address(). This commit adds the missing cases. Test coverage is added in object_address.sql for these two catalog types via the zero-OID test that exercises pg_identify_object() and pg_identify_object_as_address(). A test in event_trigger.sql verifies that DROP PROPERTY GRAPH works correctly when an event trigger is active. Author: Bertrand Drouvot <[email protected]> Reviewed-by: Michael Paquier <[email protected]> Reviewed-by: Ashutosh Bapat <[email protected]> Discussion: https://postgr.es/m/aej1DkLwhyZWmtxJ@bdtpg --- src/backend/catalog/objectaddress.c | 93 ++++++++++++++++++++ src/test/regress/expected/event_trigger.out | 17 ++++ src/test/regress/expected/object_address.out | 4 + src/test/regress/sql/event_trigger.sql | 13 +++ src/test/regress/sql/object_address.sql | 2 + 5 files changed, 129 insertions(+) 62.4% src/backend/catalog/ 25.6% src/test/regress/expected/ 11.8% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/event_trigger.out b/src/test/regress/expected/event_trigger.out index 065f586310f..ed8d5df397e 100644 --- a/src/test/regress/expected/event_trigger.out +++ b/src/test/regress/expected/event_trigger.out @@ -173,6 +173,23 @@ NOTICE: test_event_trigger: ddl_command_end CREATE USER MAPPING alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; NOTICE: test_event_trigger: ddl_command_end ALTER DEFAULT PRIVILEGES +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE TABLE t2x (i int PRIMARY KEY, j text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); +NOTICE: test_event_trigger: ddl_command_end CREATE PROPERTY GRAPH +DROP PROPERTY GRAPH gx; +NOTICE: test_event_trigger: ddl_command_end DROP PROPERTY GRAPH +DROP TABLE t1x, t2x; +NOTICE: test_event_trigger: ddl_command_end DROP TABLE -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; ERROR: permission denied to change owner of event trigger "regress_event_trigger" diff --git a/src/test/regress/expected/object_address.out b/src/test/regress/expected/object_address.out index 97227d67a54..729c3537f25 100644 --- a/src/test/regress/expected/object_address.out +++ b/src/test/regress/expected/object_address.out @@ -593,7 +593,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace @@ -653,6 +655,8 @@ ORDER BY objects.classid, objects.objid, objects.objsubid; ("(""parameter ACL"",,,)")|("(""parameter ACL"",,)")|NULL ("(""property graph element"",,,)")|("(""property graph element"",,)")|NULL ("(""property graph label"",,,)")|("(""property graph label"",,)")|NULL +("(""property graph element label"",,,)")|("(""property graph element label"",,)")|NULL ("(""property graph property"",,,)")|("(""property graph property"",,)")|NULL +("(""property graph label property"",,,)")|("(""property graph label property"",,)")|NULL -- restore normal output mode \a\t diff --git a/src/test/regress/sql/event_trigger.sql b/src/test/regress/sql/event_trigger.sql index 32e9bb58c5e..271f443378b 100644 --- a/src/test/regress/sql/event_trigger.sql +++ b/src/test/regress/sql/event_trigger.sql @@ -143,6 +143,19 @@ create user mapping for regress_evt_user server useless_server; alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +CREATE TABLE t2x (i int PRIMARY KEY, j text); + +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); + +DROP PROPERTY GRAPH gx; +DROP TABLE t1x, t2x; + -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; diff --git a/src/test/regress/sql/object_address.sql b/src/test/regress/sql/object_address.sql index 1bbe9457c1c..620dacf1045 100644 --- a/src/test/regress/sql/object_address.sql +++ b/src/test/regress/sql/object_address.sql @@ -282,7 +282,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace -- 2.34.1 --gtUR827Uq8d5gVsQ-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v3] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-23 09:27 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-23 09:27 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing them to hit the default case and error out with "unsupported object class". During DROP PROPERTY GRAPH, this manifests when an event trigger is active, because pg_event_trigger_ddl_commands() calls these functions. The same code paths are also reachable via pg_identify_object() and pg_identify_object_as_address(). This commit adds the missing cases. Test coverage is added in object_address.sql for these two catalog types and in create_property_graph.sql covering all property graph object types. A test in event_trigger.sql verifies that DROP PROPERTY GRAPH works correctly when an event trigger is active. Author: Bertrand Drouvot <[email protected]> Reviewed-by: Michael Paquier <[email protected]> Reviewed-by: Ashutosh Bapat <[email protected]> Discussion: https://postgr.es/m/aej1DkLwhyZWmtxJ@bdtpg --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 78 ++++++++++++++++ src/test/regress/expected/event_trigger.out | 17 ++++ src/test/regress/expected/object_address.out | 10 +- .../regress/sql/create_property_graph.sql | 23 +++++ src/test/regress/sql/event_trigger.sql | 13 +++ src/test/regress/sql/object_address.sql | 6 +- 7 files changed, 238 insertions(+), 2 deletions(-) 14.7% src/backend/catalog/ 75.5% src/test/regress/expected/ 9.7% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..eb9e17fb727 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -752,6 +752,84 @@ SELECT (pg_identify_object(classid, objid, objsubid)).* type | create_property_graph_tests | g2 | create_property_graph_tests.g2 (21 rows) +-- test object address functions with recursive dependency walk +-- covers all property graph object types including indirect dependents +SELECT * +FROM ( + WITH RECURSIVE deps (classid, objid, objsubid, refclassid, refobjid, refobjsubid) AS ( + SELECT classid, objid, objsubid, + refclassid, refobjid, refobjsubid + FROM pg_depend + WHERE refclassid = 'pg_class'::regclass AND + refobjid = 'create_property_graph_tests.gt'::regclass + UNION ALL + SELECT d.classid, d.objid, d.objsubid, + d.refclassid, d.refobjid, d.refobjsubid + FROM pg_depend d + JOIN deps dp ON d.refclassid = dp.classid AND d.refobjid = dp.objid AND d.refobjsubid = dp.objsubid + ) + SELECT pg_describe_object(classid, objid, objsubid) as obj, + pg_identify_object(classid, objid, objsubid) as ident, + pg_identify_object_as_address(classid, objid, objsubid) as addr + FROM deps +) s +ORDER BY obj COLLATE "C", ident::text COLLATE "C"; + obj | ident | addr +----------------------------------------------------------+----------------------------------------------------------------------------+---------------------------------------------------------------------------- + edge e of property graph gt | ("property graph element",,,"e of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,e}",{}) + edge e of property graph gt | ("property graph element",,,"e of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,e}",{}) + edge e of property graph gt | ("property graph element",,,"e of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of property graph gt | ("property graph label",,,"e of create_property_graph_tests.gt") | ("property graph label","{create_property_graph_tests,gt,e}",{}) + label v1 of property graph gt | ("property graph label",,,"v1 of create_property_graph_tests.gt") | ("property graph label","{create_property_graph_tests,gt,v1}",{}) + label v1 of vertex v1 of property graph gt | ("property graph element label",,,"v1 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v1}",{}) + label v1 of vertex v1 of property graph gt | ("property graph element label",,,"v1 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v1}",{}) + label v2 of property graph gt | ("property graph label",,,"v2 of create_property_graph_tests.gt") | ("property graph label","{create_property_graph_tests,gt,v2}",{}) + label v2 of vertex v2 of property graph gt | ("property graph element label",,,"v2 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v2}",{}) + label v2 of vertex v2 of property graph gt | ("property graph element label",,,"v2 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v2}",{}) + property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property a of property graph gt | ("property graph property",,,"a of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,a}",{}) + property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property b of property graph gt | ("property graph property",,,"b of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,b}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of property graph gt | ("property graph property",,,"c of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,c}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of property graph gt | ("property graph property",,,"k1 of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,k1}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of property graph gt | ("property graph property",,,"k2 of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,k2}",{}) + property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property m of property graph gt | ("property graph property",,,"m of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,m}",{}) + property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property n of property graph gt | ("property graph property",,,"n of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,n}",{}) + type gt | (type,create_property_graph_tests,gt,create_property_graph_tests.gt) | (type,{create_property_graph_tests.gt},{}) + type gt[] | (type,create_property_graph_tests,_gt,create_property_graph_tests.gt[]) | (type,{create_property_graph_tests.gt[]},{}) + vertex v1 of property graph gt | ("property graph element",,,"v1 of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,v1}",{}) + vertex v2 of property graph gt | ("property graph element",,,"v2 of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,v2}",{}) +(52 rows) + \a\t SELECT pg_get_propgraphdef('g2'::regclass); CREATE PROPERTY GRAPH create_property_graph_tests.g2 diff --git a/src/test/regress/expected/event_trigger.out b/src/test/regress/expected/event_trigger.out index 065f586310f..ed8d5df397e 100644 --- a/src/test/regress/expected/event_trigger.out +++ b/src/test/regress/expected/event_trigger.out @@ -173,6 +173,23 @@ NOTICE: test_event_trigger: ddl_command_end CREATE USER MAPPING alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; NOTICE: test_event_trigger: ddl_command_end ALTER DEFAULT PRIVILEGES +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE TABLE t2x (i int PRIMARY KEY, j text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); +NOTICE: test_event_trigger: ddl_command_end CREATE PROPERTY GRAPH +DROP PROPERTY GRAPH gx; +NOTICE: test_event_trigger: ddl_command_end DROP PROPERTY GRAPH +DROP TABLE t1x, t2x; +NOTICE: test_event_trigger: ddl_command_end DROP TABLE -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; ERROR: permission denied to change owner of event trigger "regress_event_trigger" diff --git a/src/test/regress/expected/object_address.out b/src/test/regress/expected/object_address.out index 97227d67a54..5e53f0b092e 100644 --- a/src/test/regress/expected/object_address.out +++ b/src/test/regress/expected/object_address.out @@ -67,7 +67,9 @@ DECLARE BEGIN FOR objtype IN VALUES ('toast table'), ('index column'), ('sequence column'), ('toast table column'), ('view column'), ('materialized view column'), - ('property graph element'), ('property graph label'), ('property graph property') + ('property graph element'), ('property graph element label'), + ('property graph label'), ('property graph label property'), + ('property graph property') LOOP BEGIN PERFORM pg_get_object_address(objtype, '{one}', '{}'); @@ -84,7 +86,9 @@ WARNING: error for toast table column: unsupported object type "toast table col WARNING: error for view column: unsupported object type "view column" WARNING: error for materialized view column: unsupported object type "materialized view column" WARNING: error for property graph element: unsupported object type "property graph element" +WARNING: error for property graph element label: unrecognized object type "property graph element label" WARNING: error for property graph label: unsupported object type "property graph label" +WARNING: error for property graph label property: unrecognized object type "property graph label property" WARNING: error for property graph property: unsupported object type "property graph property" -- miscellaneous other errors select * from pg_get_object_address('operator of access method', '{btree,integer_ops,1}', '{int4,bool}'); @@ -593,7 +597,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace @@ -653,6 +659,8 @@ ORDER BY objects.classid, objects.objid, objects.objsubid; ("(""parameter ACL"",,,)")|("(""parameter ACL"",,)")|NULL ("(""property graph element"",,,)")|("(""property graph element"",,)")|NULL ("(""property graph label"",,,)")|("(""property graph label"",,)")|NULL +("(""property graph element label"",,,)")|("(""property graph element label"",,)")|NULL ("(""property graph property"",,,)")|("(""property graph property"",,)")|NULL +("(""property graph label property"",,,)")|("(""property graph label property"",,)")|NULL -- restore normal output mode \a\t diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..9608dd5c4af 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -298,6 +298,29 @@ SELECT (pg_identify_object(classid, objid, objsubid)).* refobjid = 'create_property_graph_tests.g2'::regclass ORDER BY 1, 2, 3, 4; +-- test object address functions with recursive dependency walk +-- covers all property graph object types including indirect dependents +SELECT * +FROM ( + WITH RECURSIVE deps (classid, objid, objsubid, refclassid, refobjid, refobjsubid) AS ( + SELECT classid, objid, objsubid, + refclassid, refobjid, refobjsubid + FROM pg_depend + WHERE refclassid = 'pg_class'::regclass AND + refobjid = 'create_property_graph_tests.gt'::regclass + UNION ALL + SELECT d.classid, d.objid, d.objsubid, + d.refclassid, d.refobjid, d.refobjsubid + FROM pg_depend d + JOIN deps dp ON d.refclassid = dp.classid AND d.refobjid = dp.objid AND d.refobjsubid = dp.objsubid + ) + SELECT pg_describe_object(classid, objid, objsubid) as obj, + pg_identify_object(classid, objid, objsubid) as ident, + pg_identify_object_as_address(classid, objid, objsubid) as addr + FROM deps +) s +ORDER BY obj COLLATE "C", ident::text COLLATE "C"; + \a\t SELECT pg_get_propgraphdef('g2'::regclass); SELECT pg_get_propgraphdef('g3'::regclass); diff --git a/src/test/regress/sql/event_trigger.sql b/src/test/regress/sql/event_trigger.sql index 32e9bb58c5e..271f443378b 100644 --- a/src/test/regress/sql/event_trigger.sql +++ b/src/test/regress/sql/event_trigger.sql @@ -143,6 +143,19 @@ create user mapping for regress_evt_user server useless_server; alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +CREATE TABLE t2x (i int PRIMARY KEY, j text); + +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); + +DROP PROPERTY GRAPH gx; +DROP TABLE t1x, t2x; + -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; diff --git a/src/test/regress/sql/object_address.sql b/src/test/regress/sql/object_address.sql index 1bbe9457c1c..27109d421c7 100644 --- a/src/test/regress/sql/object_address.sql +++ b/src/test/regress/sql/object_address.sql @@ -67,7 +67,9 @@ DECLARE BEGIN FOR objtype IN VALUES ('toast table'), ('index column'), ('sequence column'), ('toast table column'), ('view column'), ('materialized view column'), - ('property graph element'), ('property graph label'), ('property graph property') + ('property graph element'), ('property graph element label'), + ('property graph label'), ('property graph label property'), + ('property graph property') LOOP BEGIN PERFORM pg_get_object_address(objtype, '{one}', '{}'); @@ -282,7 +284,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace -- 2.34.1 --R84XrR4Hgw0dH3Ec-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v2] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-23 09:27 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-23 09:27 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing them to hit the default case and error out with "unsupported object class". During DROP PROPERTY GRAPH, this manifests when an event trigger is active, because pg_event_trigger_ddl_commands() calls these functions. The same code paths are also reachable via pg_identify_object() and pg_identify_object_as_address(). This commit adds the missing cases. Test coverage is added in object_address.sql for these two catalog types via the zero-OID test that exercises pg_identify_object() and pg_identify_object_as_address(). A test in event_trigger.sql verifies that DROP PROPERTY GRAPH works correctly when an event trigger is active. Author: Bertrand Drouvot <[email protected]> Reviewed-by: Michael Paquier <[email protected]> Reviewed-by: Ashutosh Bapat <[email protected]> Discussion: https://postgr.es/m/aej1DkLwhyZWmtxJ@bdtpg --- src/backend/catalog/objectaddress.c | 93 ++++++++++++++++++++ src/test/regress/expected/event_trigger.out | 17 ++++ src/test/regress/expected/object_address.out | 4 + src/test/regress/sql/event_trigger.sql | 13 +++ src/test/regress/sql/object_address.sql | 2 + 5 files changed, 129 insertions(+) 62.4% src/backend/catalog/ 25.6% src/test/regress/expected/ 11.8% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/event_trigger.out b/src/test/regress/expected/event_trigger.out index 065f586310f..ed8d5df397e 100644 --- a/src/test/regress/expected/event_trigger.out +++ b/src/test/regress/expected/event_trigger.out @@ -173,6 +173,23 @@ NOTICE: test_event_trigger: ddl_command_end CREATE USER MAPPING alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; NOTICE: test_event_trigger: ddl_command_end ALTER DEFAULT PRIVILEGES +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE TABLE t2x (i int PRIMARY KEY, j text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); +NOTICE: test_event_trigger: ddl_command_end CREATE PROPERTY GRAPH +DROP PROPERTY GRAPH gx; +NOTICE: test_event_trigger: ddl_command_end DROP PROPERTY GRAPH +DROP TABLE t1x, t2x; +NOTICE: test_event_trigger: ddl_command_end DROP TABLE -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; ERROR: permission denied to change owner of event trigger "regress_event_trigger" diff --git a/src/test/regress/expected/object_address.out b/src/test/regress/expected/object_address.out index 97227d67a54..729c3537f25 100644 --- a/src/test/regress/expected/object_address.out +++ b/src/test/regress/expected/object_address.out @@ -593,7 +593,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace @@ -653,6 +655,8 @@ ORDER BY objects.classid, objects.objid, objects.objsubid; ("(""parameter ACL"",,,)")|("(""parameter ACL"",,)")|NULL ("(""property graph element"",,,)")|("(""property graph element"",,)")|NULL ("(""property graph label"",,,)")|("(""property graph label"",,)")|NULL +("(""property graph element label"",,,)")|("(""property graph element label"",,)")|NULL ("(""property graph property"",,,)")|("(""property graph property"",,)")|NULL +("(""property graph label property"",,,)")|("(""property graph label property"",,)")|NULL -- restore normal output mode \a\t diff --git a/src/test/regress/sql/event_trigger.sql b/src/test/regress/sql/event_trigger.sql index 32e9bb58c5e..271f443378b 100644 --- a/src/test/regress/sql/event_trigger.sql +++ b/src/test/regress/sql/event_trigger.sql @@ -143,6 +143,19 @@ create user mapping for regress_evt_user server useless_server; alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +CREATE TABLE t2x (i int PRIMARY KEY, j text); + +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); + +DROP PROPERTY GRAPH gx; +DROP TABLE t1x, t2x; + -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; diff --git a/src/test/regress/sql/object_address.sql b/src/test/regress/sql/object_address.sql index 1bbe9457c1c..620dacf1045 100644 --- a/src/test/regress/sql/object_address.sql +++ b/src/test/regress/sql/object_address.sql @@ -282,7 +282,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace -- 2.34.1 --gtUR827Uq8d5gVsQ-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v2] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-23 09:27 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-23 09:27 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing them to hit the default case and error out with "unsupported object class". During DROP PROPERTY GRAPH, this manifests when an event trigger is active, because pg_event_trigger_ddl_commands() calls these functions. The same code paths are also reachable via pg_identify_object() and pg_identify_object_as_address(). This commit adds the missing cases. Test coverage is added in object_address.sql for these two catalog types via the zero-OID test that exercises pg_identify_object() and pg_identify_object_as_address(). A test in event_trigger.sql verifies that DROP PROPERTY GRAPH works correctly when an event trigger is active. Author: Bertrand Drouvot <[email protected]> Reviewed-by: Michael Paquier <[email protected]> Reviewed-by: Ashutosh Bapat <[email protected]> Discussion: https://postgr.es/m/aej1DkLwhyZWmtxJ@bdtpg --- src/backend/catalog/objectaddress.c | 93 ++++++++++++++++++++ src/test/regress/expected/event_trigger.out | 17 ++++ src/test/regress/expected/object_address.out | 4 + src/test/regress/sql/event_trigger.sql | 13 +++ src/test/regress/sql/object_address.sql | 2 + 5 files changed, 129 insertions(+) 62.4% src/backend/catalog/ 25.6% src/test/regress/expected/ 11.8% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/event_trigger.out b/src/test/regress/expected/event_trigger.out index 065f586310f..ed8d5df397e 100644 --- a/src/test/regress/expected/event_trigger.out +++ b/src/test/regress/expected/event_trigger.out @@ -173,6 +173,23 @@ NOTICE: test_event_trigger: ddl_command_end CREATE USER MAPPING alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; NOTICE: test_event_trigger: ddl_command_end ALTER DEFAULT PRIVILEGES +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE TABLE t2x (i int PRIMARY KEY, j text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); +NOTICE: test_event_trigger: ddl_command_end CREATE PROPERTY GRAPH +DROP PROPERTY GRAPH gx; +NOTICE: test_event_trigger: ddl_command_end DROP PROPERTY GRAPH +DROP TABLE t1x, t2x; +NOTICE: test_event_trigger: ddl_command_end DROP TABLE -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; ERROR: permission denied to change owner of event trigger "regress_event_trigger" diff --git a/src/test/regress/expected/object_address.out b/src/test/regress/expected/object_address.out index 97227d67a54..729c3537f25 100644 --- a/src/test/regress/expected/object_address.out +++ b/src/test/regress/expected/object_address.out @@ -593,7 +593,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace @@ -653,6 +655,8 @@ ORDER BY objects.classid, objects.objid, objects.objsubid; ("(""parameter ACL"",,,)")|("(""parameter ACL"",,)")|NULL ("(""property graph element"",,,)")|("(""property graph element"",,)")|NULL ("(""property graph label"",,,)")|("(""property graph label"",,)")|NULL +("(""property graph element label"",,,)")|("(""property graph element label"",,)")|NULL ("(""property graph property"",,,)")|("(""property graph property"",,)")|NULL +("(""property graph label property"",,,)")|("(""property graph label property"",,)")|NULL -- restore normal output mode \a\t diff --git a/src/test/regress/sql/event_trigger.sql b/src/test/regress/sql/event_trigger.sql index 32e9bb58c5e..271f443378b 100644 --- a/src/test/regress/sql/event_trigger.sql +++ b/src/test/regress/sql/event_trigger.sql @@ -143,6 +143,19 @@ create user mapping for regress_evt_user server useless_server; alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +CREATE TABLE t2x (i int PRIMARY KEY, j text); + +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); + +DROP PROPERTY GRAPH gx; +DROP TABLE t1x, t2x; + -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; diff --git a/src/test/regress/sql/object_address.sql b/src/test/regress/sql/object_address.sql index 1bbe9457c1c..620dacf1045 100644 --- a/src/test/regress/sql/object_address.sql +++ b/src/test/regress/sql/object_address.sql @@ -282,7 +282,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace -- 2.34.1 --gtUR827Uq8d5gVsQ-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v3] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-23 09:27 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-23 09:27 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing them to hit the default case and error out with "unsupported object class". During DROP PROPERTY GRAPH, this manifests when an event trigger is active, because pg_event_trigger_ddl_commands() calls these functions. The same code paths are also reachable via pg_identify_object() and pg_identify_object_as_address(). This commit adds the missing cases. Test coverage is added in object_address.sql for these two catalog types and in create_property_graph.sql covering all property graph object types. A test in event_trigger.sql verifies that DROP PROPERTY GRAPH works correctly when an event trigger is active. Author: Bertrand Drouvot <[email protected]> Reviewed-by: Michael Paquier <[email protected]> Reviewed-by: Ashutosh Bapat <[email protected]> Discussion: https://postgr.es/m/aej1DkLwhyZWmtxJ@bdtpg --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 78 ++++++++++++++++ src/test/regress/expected/event_trigger.out | 17 ++++ src/test/regress/expected/object_address.out | 10 +- .../regress/sql/create_property_graph.sql | 23 +++++ src/test/regress/sql/event_trigger.sql | 13 +++ src/test/regress/sql/object_address.sql | 6 +- 7 files changed, 238 insertions(+), 2 deletions(-) 14.7% src/backend/catalog/ 75.5% src/test/regress/expected/ 9.7% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..eb9e17fb727 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -752,6 +752,84 @@ SELECT (pg_identify_object(classid, objid, objsubid)).* type | create_property_graph_tests | g2 | create_property_graph_tests.g2 (21 rows) +-- test object address functions with recursive dependency walk +-- covers all property graph object types including indirect dependents +SELECT * +FROM ( + WITH RECURSIVE deps (classid, objid, objsubid, refclassid, refobjid, refobjsubid) AS ( + SELECT classid, objid, objsubid, + refclassid, refobjid, refobjsubid + FROM pg_depend + WHERE refclassid = 'pg_class'::regclass AND + refobjid = 'create_property_graph_tests.gt'::regclass + UNION ALL + SELECT d.classid, d.objid, d.objsubid, + d.refclassid, d.refobjid, d.refobjsubid + FROM pg_depend d + JOIN deps dp ON d.refclassid = dp.classid AND d.refobjid = dp.objid AND d.refobjsubid = dp.objsubid + ) + SELECT pg_describe_object(classid, objid, objsubid) as obj, + pg_identify_object(classid, objid, objsubid) as ident, + pg_identify_object_as_address(classid, objid, objsubid) as addr + FROM deps +) s +ORDER BY obj COLLATE "C", ident::text COLLATE "C"; + obj | ident | addr +----------------------------------------------------------+----------------------------------------------------------------------------+---------------------------------------------------------------------------- + edge e of property graph gt | ("property graph element",,,"e of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,e}",{}) + edge e of property graph gt | ("property graph element",,,"e of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,e}",{}) + edge e of property graph gt | ("property graph element",,,"e of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of property graph gt | ("property graph label",,,"e of create_property_graph_tests.gt") | ("property graph label","{create_property_graph_tests,gt,e}",{}) + label v1 of property graph gt | ("property graph label",,,"v1 of create_property_graph_tests.gt") | ("property graph label","{create_property_graph_tests,gt,v1}",{}) + label v1 of vertex v1 of property graph gt | ("property graph element label",,,"v1 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v1}",{}) + label v1 of vertex v1 of property graph gt | ("property graph element label",,,"v1 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v1}",{}) + label v2 of property graph gt | ("property graph label",,,"v2 of create_property_graph_tests.gt") | ("property graph label","{create_property_graph_tests,gt,v2}",{}) + label v2 of vertex v2 of property graph gt | ("property graph element label",,,"v2 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v2}",{}) + label v2 of vertex v2 of property graph gt | ("property graph element label",,,"v2 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v2}",{}) + property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property a of property graph gt | ("property graph property",,,"a of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,a}",{}) + property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property b of property graph gt | ("property graph property",,,"b of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,b}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of property graph gt | ("property graph property",,,"c of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,c}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of property graph gt | ("property graph property",,,"k1 of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,k1}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of property graph gt | ("property graph property",,,"k2 of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,k2}",{}) + property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property m of property graph gt | ("property graph property",,,"m of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,m}",{}) + property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property n of property graph gt | ("property graph property",,,"n of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,n}",{}) + type gt | (type,create_property_graph_tests,gt,create_property_graph_tests.gt) | (type,{create_property_graph_tests.gt},{}) + type gt[] | (type,create_property_graph_tests,_gt,create_property_graph_tests.gt[]) | (type,{create_property_graph_tests.gt[]},{}) + vertex v1 of property graph gt | ("property graph element",,,"v1 of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,v1}",{}) + vertex v2 of property graph gt | ("property graph element",,,"v2 of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,v2}",{}) +(52 rows) + \a\t SELECT pg_get_propgraphdef('g2'::regclass); CREATE PROPERTY GRAPH create_property_graph_tests.g2 diff --git a/src/test/regress/expected/event_trigger.out b/src/test/regress/expected/event_trigger.out index 065f586310f..ed8d5df397e 100644 --- a/src/test/regress/expected/event_trigger.out +++ b/src/test/regress/expected/event_trigger.out @@ -173,6 +173,23 @@ NOTICE: test_event_trigger: ddl_command_end CREATE USER MAPPING alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; NOTICE: test_event_trigger: ddl_command_end ALTER DEFAULT PRIVILEGES +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE TABLE t2x (i int PRIMARY KEY, j text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); +NOTICE: test_event_trigger: ddl_command_end CREATE PROPERTY GRAPH +DROP PROPERTY GRAPH gx; +NOTICE: test_event_trigger: ddl_command_end DROP PROPERTY GRAPH +DROP TABLE t1x, t2x; +NOTICE: test_event_trigger: ddl_command_end DROP TABLE -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; ERROR: permission denied to change owner of event trigger "regress_event_trigger" diff --git a/src/test/regress/expected/object_address.out b/src/test/regress/expected/object_address.out index 97227d67a54..5e53f0b092e 100644 --- a/src/test/regress/expected/object_address.out +++ b/src/test/regress/expected/object_address.out @@ -67,7 +67,9 @@ DECLARE BEGIN FOR objtype IN VALUES ('toast table'), ('index column'), ('sequence column'), ('toast table column'), ('view column'), ('materialized view column'), - ('property graph element'), ('property graph label'), ('property graph property') + ('property graph element'), ('property graph element label'), + ('property graph label'), ('property graph label property'), + ('property graph property') LOOP BEGIN PERFORM pg_get_object_address(objtype, '{one}', '{}'); @@ -84,7 +86,9 @@ WARNING: error for toast table column: unsupported object type "toast table col WARNING: error for view column: unsupported object type "view column" WARNING: error for materialized view column: unsupported object type "materialized view column" WARNING: error for property graph element: unsupported object type "property graph element" +WARNING: error for property graph element label: unrecognized object type "property graph element label" WARNING: error for property graph label: unsupported object type "property graph label" +WARNING: error for property graph label property: unrecognized object type "property graph label property" WARNING: error for property graph property: unsupported object type "property graph property" -- miscellaneous other errors select * from pg_get_object_address('operator of access method', '{btree,integer_ops,1}', '{int4,bool}'); @@ -593,7 +597,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace @@ -653,6 +659,8 @@ ORDER BY objects.classid, objects.objid, objects.objsubid; ("(""parameter ACL"",,,)")|("(""parameter ACL"",,)")|NULL ("(""property graph element"",,,)")|("(""property graph element"",,)")|NULL ("(""property graph label"",,,)")|("(""property graph label"",,)")|NULL +("(""property graph element label"",,,)")|("(""property graph element label"",,)")|NULL ("(""property graph property"",,,)")|("(""property graph property"",,)")|NULL +("(""property graph label property"",,,)")|("(""property graph label property"",,)")|NULL -- restore normal output mode \a\t diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..9608dd5c4af 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -298,6 +298,29 @@ SELECT (pg_identify_object(classid, objid, objsubid)).* refobjid = 'create_property_graph_tests.g2'::regclass ORDER BY 1, 2, 3, 4; +-- test object address functions with recursive dependency walk +-- covers all property graph object types including indirect dependents +SELECT * +FROM ( + WITH RECURSIVE deps (classid, objid, objsubid, refclassid, refobjid, refobjsubid) AS ( + SELECT classid, objid, objsubid, + refclassid, refobjid, refobjsubid + FROM pg_depend + WHERE refclassid = 'pg_class'::regclass AND + refobjid = 'create_property_graph_tests.gt'::regclass + UNION ALL + SELECT d.classid, d.objid, d.objsubid, + d.refclassid, d.refobjid, d.refobjsubid + FROM pg_depend d + JOIN deps dp ON d.refclassid = dp.classid AND d.refobjid = dp.objid AND d.refobjsubid = dp.objsubid + ) + SELECT pg_describe_object(classid, objid, objsubid) as obj, + pg_identify_object(classid, objid, objsubid) as ident, + pg_identify_object_as_address(classid, objid, objsubid) as addr + FROM deps +) s +ORDER BY obj COLLATE "C", ident::text COLLATE "C"; + \a\t SELECT pg_get_propgraphdef('g2'::regclass); SELECT pg_get_propgraphdef('g3'::regclass); diff --git a/src/test/regress/sql/event_trigger.sql b/src/test/regress/sql/event_trigger.sql index 32e9bb58c5e..271f443378b 100644 --- a/src/test/regress/sql/event_trigger.sql +++ b/src/test/regress/sql/event_trigger.sql @@ -143,6 +143,19 @@ create user mapping for regress_evt_user server useless_server; alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +CREATE TABLE t2x (i int PRIMARY KEY, j text); + +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); + +DROP PROPERTY GRAPH gx; +DROP TABLE t1x, t2x; + -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; diff --git a/src/test/regress/sql/object_address.sql b/src/test/regress/sql/object_address.sql index 1bbe9457c1c..27109d421c7 100644 --- a/src/test/regress/sql/object_address.sql +++ b/src/test/regress/sql/object_address.sql @@ -67,7 +67,9 @@ DECLARE BEGIN FOR objtype IN VALUES ('toast table'), ('index column'), ('sequence column'), ('toast table column'), ('view column'), ('materialized view column'), - ('property graph element'), ('property graph label'), ('property graph property') + ('property graph element'), ('property graph element label'), + ('property graph label'), ('property graph label property'), + ('property graph property') LOOP BEGIN PERFORM pg_get_object_address(objtype, '{one}', '{}'); @@ -282,7 +284,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace -- 2.34.1 --R84XrR4Hgw0dH3Ec-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v2] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-23 09:27 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-23 09:27 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing them to hit the default case and error out with "unsupported object class". During DROP PROPERTY GRAPH, this manifests when an event trigger is active, because pg_event_trigger_ddl_commands() calls these functions. The same code paths are also reachable via pg_identify_object() and pg_identify_object_as_address(). This commit adds the missing cases. Test coverage is added in object_address.sql for these two catalog types via the zero-OID test that exercises pg_identify_object() and pg_identify_object_as_address(). A test in event_trigger.sql verifies that DROP PROPERTY GRAPH works correctly when an event trigger is active. Author: Bertrand Drouvot <[email protected]> Reviewed-by: Michael Paquier <[email protected]> Reviewed-by: Ashutosh Bapat <[email protected]> Discussion: https://postgr.es/m/aej1DkLwhyZWmtxJ@bdtpg --- src/backend/catalog/objectaddress.c | 93 ++++++++++++++++++++ src/test/regress/expected/event_trigger.out | 17 ++++ src/test/regress/expected/object_address.out | 4 + src/test/regress/sql/event_trigger.sql | 13 +++ src/test/regress/sql/object_address.sql | 2 + 5 files changed, 129 insertions(+) 62.4% src/backend/catalog/ 25.6% src/test/regress/expected/ 11.8% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/event_trigger.out b/src/test/regress/expected/event_trigger.out index 065f586310f..ed8d5df397e 100644 --- a/src/test/regress/expected/event_trigger.out +++ b/src/test/regress/expected/event_trigger.out @@ -173,6 +173,23 @@ NOTICE: test_event_trigger: ddl_command_end CREATE USER MAPPING alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; NOTICE: test_event_trigger: ddl_command_end ALTER DEFAULT PRIVILEGES +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE TABLE t2x (i int PRIMARY KEY, j text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); +NOTICE: test_event_trigger: ddl_command_end CREATE PROPERTY GRAPH +DROP PROPERTY GRAPH gx; +NOTICE: test_event_trigger: ddl_command_end DROP PROPERTY GRAPH +DROP TABLE t1x, t2x; +NOTICE: test_event_trigger: ddl_command_end DROP TABLE -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; ERROR: permission denied to change owner of event trigger "regress_event_trigger" diff --git a/src/test/regress/expected/object_address.out b/src/test/regress/expected/object_address.out index 97227d67a54..729c3537f25 100644 --- a/src/test/regress/expected/object_address.out +++ b/src/test/regress/expected/object_address.out @@ -593,7 +593,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace @@ -653,6 +655,8 @@ ORDER BY objects.classid, objects.objid, objects.objsubid; ("(""parameter ACL"",,,)")|("(""parameter ACL"",,)")|NULL ("(""property graph element"",,,)")|("(""property graph element"",,)")|NULL ("(""property graph label"",,,)")|("(""property graph label"",,)")|NULL +("(""property graph element label"",,,)")|("(""property graph element label"",,)")|NULL ("(""property graph property"",,,)")|("(""property graph property"",,)")|NULL +("(""property graph label property"",,,)")|("(""property graph label property"",,)")|NULL -- restore normal output mode \a\t diff --git a/src/test/regress/sql/event_trigger.sql b/src/test/regress/sql/event_trigger.sql index 32e9bb58c5e..271f443378b 100644 --- a/src/test/regress/sql/event_trigger.sql +++ b/src/test/regress/sql/event_trigger.sql @@ -143,6 +143,19 @@ create user mapping for regress_evt_user server useless_server; alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +CREATE TABLE t2x (i int PRIMARY KEY, j text); + +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); + +DROP PROPERTY GRAPH gx; +DROP TABLE t1x, t2x; + -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; diff --git a/src/test/regress/sql/object_address.sql b/src/test/regress/sql/object_address.sql index 1bbe9457c1c..620dacf1045 100644 --- a/src/test/regress/sql/object_address.sql +++ b/src/test/regress/sql/object_address.sql @@ -282,7 +282,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace -- 2.34.1 --gtUR827Uq8d5gVsQ-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v2] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-23 09:27 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-23 09:27 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing them to hit the default case and error out with "unsupported object class". During DROP PROPERTY GRAPH, this manifests when an event trigger is active, because pg_event_trigger_ddl_commands() calls these functions. The same code paths are also reachable via pg_identify_object() and pg_identify_object_as_address(). This commit adds the missing cases. Test coverage is added in object_address.sql for these two catalog types via the zero-OID test that exercises pg_identify_object() and pg_identify_object_as_address(). A test in event_trigger.sql verifies that DROP PROPERTY GRAPH works correctly when an event trigger is active. Author: Bertrand Drouvot <[email protected]> Reviewed-by: Michael Paquier <[email protected]> Reviewed-by: Ashutosh Bapat <[email protected]> Discussion: https://postgr.es/m/aej1DkLwhyZWmtxJ@bdtpg --- src/backend/catalog/objectaddress.c | 93 ++++++++++++++++++++ src/test/regress/expected/event_trigger.out | 17 ++++ src/test/regress/expected/object_address.out | 4 + src/test/regress/sql/event_trigger.sql | 13 +++ src/test/regress/sql/object_address.sql | 2 + 5 files changed, 129 insertions(+) 62.4% src/backend/catalog/ 25.6% src/test/regress/expected/ 11.8% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/event_trigger.out b/src/test/regress/expected/event_trigger.out index 065f586310f..ed8d5df397e 100644 --- a/src/test/regress/expected/event_trigger.out +++ b/src/test/regress/expected/event_trigger.out @@ -173,6 +173,23 @@ NOTICE: test_event_trigger: ddl_command_end CREATE USER MAPPING alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; NOTICE: test_event_trigger: ddl_command_end ALTER DEFAULT PRIVILEGES +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE TABLE t2x (i int PRIMARY KEY, j text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); +NOTICE: test_event_trigger: ddl_command_end CREATE PROPERTY GRAPH +DROP PROPERTY GRAPH gx; +NOTICE: test_event_trigger: ddl_command_end DROP PROPERTY GRAPH +DROP TABLE t1x, t2x; +NOTICE: test_event_trigger: ddl_command_end DROP TABLE -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; ERROR: permission denied to change owner of event trigger "regress_event_trigger" diff --git a/src/test/regress/expected/object_address.out b/src/test/regress/expected/object_address.out index 97227d67a54..729c3537f25 100644 --- a/src/test/regress/expected/object_address.out +++ b/src/test/regress/expected/object_address.out @@ -593,7 +593,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace @@ -653,6 +655,8 @@ ORDER BY objects.classid, objects.objid, objects.objsubid; ("(""parameter ACL"",,,)")|("(""parameter ACL"",,)")|NULL ("(""property graph element"",,,)")|("(""property graph element"",,)")|NULL ("(""property graph label"",,,)")|("(""property graph label"",,)")|NULL +("(""property graph element label"",,,)")|("(""property graph element label"",,)")|NULL ("(""property graph property"",,,)")|("(""property graph property"",,)")|NULL +("(""property graph label property"",,,)")|("(""property graph label property"",,)")|NULL -- restore normal output mode \a\t diff --git a/src/test/regress/sql/event_trigger.sql b/src/test/regress/sql/event_trigger.sql index 32e9bb58c5e..271f443378b 100644 --- a/src/test/regress/sql/event_trigger.sql +++ b/src/test/regress/sql/event_trigger.sql @@ -143,6 +143,19 @@ create user mapping for regress_evt_user server useless_server; alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +CREATE TABLE t2x (i int PRIMARY KEY, j text); + +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); + +DROP PROPERTY GRAPH gx; +DROP TABLE t1x, t2x; + -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; diff --git a/src/test/regress/sql/object_address.sql b/src/test/regress/sql/object_address.sql index 1bbe9457c1c..620dacf1045 100644 --- a/src/test/regress/sql/object_address.sql +++ b/src/test/regress/sql/object_address.sql @@ -282,7 +282,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace -- 2.34.1 --gtUR827Uq8d5gVsQ-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v3] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-23 09:27 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-23 09:27 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing them to hit the default case and error out with "unsupported object class". During DROP PROPERTY GRAPH, this manifests when an event trigger is active, because pg_event_trigger_ddl_commands() calls these functions. The same code paths are also reachable via pg_identify_object() and pg_identify_object_as_address(). This commit adds the missing cases. Test coverage is added in object_address.sql for these two catalog types and in create_property_graph.sql covering all property graph object types. A test in event_trigger.sql verifies that DROP PROPERTY GRAPH works correctly when an event trigger is active. Author: Bertrand Drouvot <[email protected]> Reviewed-by: Michael Paquier <[email protected]> Reviewed-by: Ashutosh Bapat <[email protected]> Discussion: https://postgr.es/m/aej1DkLwhyZWmtxJ@bdtpg --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 78 ++++++++++++++++ src/test/regress/expected/event_trigger.out | 17 ++++ src/test/regress/expected/object_address.out | 10 +- .../regress/sql/create_property_graph.sql | 23 +++++ src/test/regress/sql/event_trigger.sql | 13 +++ src/test/regress/sql/object_address.sql | 6 +- 7 files changed, 238 insertions(+), 2 deletions(-) 14.7% src/backend/catalog/ 75.5% src/test/regress/expected/ 9.7% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..eb9e17fb727 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -752,6 +752,84 @@ SELECT (pg_identify_object(classid, objid, objsubid)).* type | create_property_graph_tests | g2 | create_property_graph_tests.g2 (21 rows) +-- test object address functions with recursive dependency walk +-- covers all property graph object types including indirect dependents +SELECT * +FROM ( + WITH RECURSIVE deps (classid, objid, objsubid, refclassid, refobjid, refobjsubid) AS ( + SELECT classid, objid, objsubid, + refclassid, refobjid, refobjsubid + FROM pg_depend + WHERE refclassid = 'pg_class'::regclass AND + refobjid = 'create_property_graph_tests.gt'::regclass + UNION ALL + SELECT d.classid, d.objid, d.objsubid, + d.refclassid, d.refobjid, d.refobjsubid + FROM pg_depend d + JOIN deps dp ON d.refclassid = dp.classid AND d.refobjid = dp.objid AND d.refobjsubid = dp.objsubid + ) + SELECT pg_describe_object(classid, objid, objsubid) as obj, + pg_identify_object(classid, objid, objsubid) as ident, + pg_identify_object_as_address(classid, objid, objsubid) as addr + FROM deps +) s +ORDER BY obj COLLATE "C", ident::text COLLATE "C"; + obj | ident | addr +----------------------------------------------------------+----------------------------------------------------------------------------+---------------------------------------------------------------------------- + edge e of property graph gt | ("property graph element",,,"e of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,e}",{}) + edge e of property graph gt | ("property graph element",,,"e of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,e}",{}) + edge e of property graph gt | ("property graph element",,,"e of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of property graph gt | ("property graph label",,,"e of create_property_graph_tests.gt") | ("property graph label","{create_property_graph_tests,gt,e}",{}) + label v1 of property graph gt | ("property graph label",,,"v1 of create_property_graph_tests.gt") | ("property graph label","{create_property_graph_tests,gt,v1}",{}) + label v1 of vertex v1 of property graph gt | ("property graph element label",,,"v1 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v1}",{}) + label v1 of vertex v1 of property graph gt | ("property graph element label",,,"v1 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v1}",{}) + label v2 of property graph gt | ("property graph label",,,"v2 of create_property_graph_tests.gt") | ("property graph label","{create_property_graph_tests,gt,v2}",{}) + label v2 of vertex v2 of property graph gt | ("property graph element label",,,"v2 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v2}",{}) + label v2 of vertex v2 of property graph gt | ("property graph element label",,,"v2 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v2}",{}) + property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property a of property graph gt | ("property graph property",,,"a of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,a}",{}) + property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property b of property graph gt | ("property graph property",,,"b of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,b}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of property graph gt | ("property graph property",,,"c of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,c}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of property graph gt | ("property graph property",,,"k1 of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,k1}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of property graph gt | ("property graph property",,,"k2 of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,k2}",{}) + property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property m of property graph gt | ("property graph property",,,"m of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,m}",{}) + property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property n of property graph gt | ("property graph property",,,"n of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,n}",{}) + type gt | (type,create_property_graph_tests,gt,create_property_graph_tests.gt) | (type,{create_property_graph_tests.gt},{}) + type gt[] | (type,create_property_graph_tests,_gt,create_property_graph_tests.gt[]) | (type,{create_property_graph_tests.gt[]},{}) + vertex v1 of property graph gt | ("property graph element",,,"v1 of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,v1}",{}) + vertex v2 of property graph gt | ("property graph element",,,"v2 of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,v2}",{}) +(52 rows) + \a\t SELECT pg_get_propgraphdef('g2'::regclass); CREATE PROPERTY GRAPH create_property_graph_tests.g2 diff --git a/src/test/regress/expected/event_trigger.out b/src/test/regress/expected/event_trigger.out index 065f586310f..ed8d5df397e 100644 --- a/src/test/regress/expected/event_trigger.out +++ b/src/test/regress/expected/event_trigger.out @@ -173,6 +173,23 @@ NOTICE: test_event_trigger: ddl_command_end CREATE USER MAPPING alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; NOTICE: test_event_trigger: ddl_command_end ALTER DEFAULT PRIVILEGES +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE TABLE t2x (i int PRIMARY KEY, j text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); +NOTICE: test_event_trigger: ddl_command_end CREATE PROPERTY GRAPH +DROP PROPERTY GRAPH gx; +NOTICE: test_event_trigger: ddl_command_end DROP PROPERTY GRAPH +DROP TABLE t1x, t2x; +NOTICE: test_event_trigger: ddl_command_end DROP TABLE -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; ERROR: permission denied to change owner of event trigger "regress_event_trigger" diff --git a/src/test/regress/expected/object_address.out b/src/test/regress/expected/object_address.out index 97227d67a54..5e53f0b092e 100644 --- a/src/test/regress/expected/object_address.out +++ b/src/test/regress/expected/object_address.out @@ -67,7 +67,9 @@ DECLARE BEGIN FOR objtype IN VALUES ('toast table'), ('index column'), ('sequence column'), ('toast table column'), ('view column'), ('materialized view column'), - ('property graph element'), ('property graph label'), ('property graph property') + ('property graph element'), ('property graph element label'), + ('property graph label'), ('property graph label property'), + ('property graph property') LOOP BEGIN PERFORM pg_get_object_address(objtype, '{one}', '{}'); @@ -84,7 +86,9 @@ WARNING: error for toast table column: unsupported object type "toast table col WARNING: error for view column: unsupported object type "view column" WARNING: error for materialized view column: unsupported object type "materialized view column" WARNING: error for property graph element: unsupported object type "property graph element" +WARNING: error for property graph element label: unrecognized object type "property graph element label" WARNING: error for property graph label: unsupported object type "property graph label" +WARNING: error for property graph label property: unrecognized object type "property graph label property" WARNING: error for property graph property: unsupported object type "property graph property" -- miscellaneous other errors select * from pg_get_object_address('operator of access method', '{btree,integer_ops,1}', '{int4,bool}'); @@ -593,7 +597,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace @@ -653,6 +659,8 @@ ORDER BY objects.classid, objects.objid, objects.objsubid; ("(""parameter ACL"",,,)")|("(""parameter ACL"",,)")|NULL ("(""property graph element"",,,)")|("(""property graph element"",,)")|NULL ("(""property graph label"",,,)")|("(""property graph label"",,)")|NULL +("(""property graph element label"",,,)")|("(""property graph element label"",,)")|NULL ("(""property graph property"",,,)")|("(""property graph property"",,)")|NULL +("(""property graph label property"",,,)")|("(""property graph label property"",,)")|NULL -- restore normal output mode \a\t diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..9608dd5c4af 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -298,6 +298,29 @@ SELECT (pg_identify_object(classid, objid, objsubid)).* refobjid = 'create_property_graph_tests.g2'::regclass ORDER BY 1, 2, 3, 4; +-- test object address functions with recursive dependency walk +-- covers all property graph object types including indirect dependents +SELECT * +FROM ( + WITH RECURSIVE deps (classid, objid, objsubid, refclassid, refobjid, refobjsubid) AS ( + SELECT classid, objid, objsubid, + refclassid, refobjid, refobjsubid + FROM pg_depend + WHERE refclassid = 'pg_class'::regclass AND + refobjid = 'create_property_graph_tests.gt'::regclass + UNION ALL + SELECT d.classid, d.objid, d.objsubid, + d.refclassid, d.refobjid, d.refobjsubid + FROM pg_depend d + JOIN deps dp ON d.refclassid = dp.classid AND d.refobjid = dp.objid AND d.refobjsubid = dp.objsubid + ) + SELECT pg_describe_object(classid, objid, objsubid) as obj, + pg_identify_object(classid, objid, objsubid) as ident, + pg_identify_object_as_address(classid, objid, objsubid) as addr + FROM deps +) s +ORDER BY obj COLLATE "C", ident::text COLLATE "C"; + \a\t SELECT pg_get_propgraphdef('g2'::regclass); SELECT pg_get_propgraphdef('g3'::regclass); diff --git a/src/test/regress/sql/event_trigger.sql b/src/test/regress/sql/event_trigger.sql index 32e9bb58c5e..271f443378b 100644 --- a/src/test/regress/sql/event_trigger.sql +++ b/src/test/regress/sql/event_trigger.sql @@ -143,6 +143,19 @@ create user mapping for regress_evt_user server useless_server; alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +CREATE TABLE t2x (i int PRIMARY KEY, j text); + +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); + +DROP PROPERTY GRAPH gx; +DROP TABLE t1x, t2x; + -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; diff --git a/src/test/regress/sql/object_address.sql b/src/test/regress/sql/object_address.sql index 1bbe9457c1c..27109d421c7 100644 --- a/src/test/regress/sql/object_address.sql +++ b/src/test/regress/sql/object_address.sql @@ -67,7 +67,9 @@ DECLARE BEGIN FOR objtype IN VALUES ('toast table'), ('index column'), ('sequence column'), ('toast table column'), ('view column'), ('materialized view column'), - ('property graph element'), ('property graph label'), ('property graph property') + ('property graph element'), ('property graph element label'), + ('property graph label'), ('property graph label property'), + ('property graph property') LOOP BEGIN PERFORM pg_get_object_address(objtype, '{one}', '{}'); @@ -282,7 +284,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace -- 2.34.1 --R84XrR4Hgw0dH3Ec-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v2] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-23 09:27 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-23 09:27 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing them to hit the default case and error out with "unsupported object class". During DROP PROPERTY GRAPH, this manifests when an event trigger is active, because pg_event_trigger_ddl_commands() calls these functions. The same code paths are also reachable via pg_identify_object() and pg_identify_object_as_address(). This commit adds the missing cases. Test coverage is added in object_address.sql for these two catalog types via the zero-OID test that exercises pg_identify_object() and pg_identify_object_as_address(). A test in event_trigger.sql verifies that DROP PROPERTY GRAPH works correctly when an event trigger is active. Author: Bertrand Drouvot <[email protected]> Reviewed-by: Michael Paquier <[email protected]> Reviewed-by: Ashutosh Bapat <[email protected]> Discussion: https://postgr.es/m/aej1DkLwhyZWmtxJ@bdtpg --- src/backend/catalog/objectaddress.c | 93 ++++++++++++++++++++ src/test/regress/expected/event_trigger.out | 17 ++++ src/test/regress/expected/object_address.out | 4 + src/test/regress/sql/event_trigger.sql | 13 +++ src/test/regress/sql/object_address.sql | 2 + 5 files changed, 129 insertions(+) 62.4% src/backend/catalog/ 25.6% src/test/regress/expected/ 11.8% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/event_trigger.out b/src/test/regress/expected/event_trigger.out index 065f586310f..ed8d5df397e 100644 --- a/src/test/regress/expected/event_trigger.out +++ b/src/test/regress/expected/event_trigger.out @@ -173,6 +173,23 @@ NOTICE: test_event_trigger: ddl_command_end CREATE USER MAPPING alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; NOTICE: test_event_trigger: ddl_command_end ALTER DEFAULT PRIVILEGES +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE TABLE t2x (i int PRIMARY KEY, j text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); +NOTICE: test_event_trigger: ddl_command_end CREATE PROPERTY GRAPH +DROP PROPERTY GRAPH gx; +NOTICE: test_event_trigger: ddl_command_end DROP PROPERTY GRAPH +DROP TABLE t1x, t2x; +NOTICE: test_event_trigger: ddl_command_end DROP TABLE -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; ERROR: permission denied to change owner of event trigger "regress_event_trigger" diff --git a/src/test/regress/expected/object_address.out b/src/test/regress/expected/object_address.out index 97227d67a54..729c3537f25 100644 --- a/src/test/regress/expected/object_address.out +++ b/src/test/regress/expected/object_address.out @@ -593,7 +593,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace @@ -653,6 +655,8 @@ ORDER BY objects.classid, objects.objid, objects.objsubid; ("(""parameter ACL"",,,)")|("(""parameter ACL"",,)")|NULL ("(""property graph element"",,,)")|("(""property graph element"",,)")|NULL ("(""property graph label"",,,)")|("(""property graph label"",,)")|NULL +("(""property graph element label"",,,)")|("(""property graph element label"",,)")|NULL ("(""property graph property"",,,)")|("(""property graph property"",,)")|NULL +("(""property graph label property"",,,)")|("(""property graph label property"",,)")|NULL -- restore normal output mode \a\t diff --git a/src/test/regress/sql/event_trigger.sql b/src/test/regress/sql/event_trigger.sql index 32e9bb58c5e..271f443378b 100644 --- a/src/test/regress/sql/event_trigger.sql +++ b/src/test/regress/sql/event_trigger.sql @@ -143,6 +143,19 @@ create user mapping for regress_evt_user server useless_server; alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +CREATE TABLE t2x (i int PRIMARY KEY, j text); + +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); + +DROP PROPERTY GRAPH gx; +DROP TABLE t1x, t2x; + -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; diff --git a/src/test/regress/sql/object_address.sql b/src/test/regress/sql/object_address.sql index 1bbe9457c1c..620dacf1045 100644 --- a/src/test/regress/sql/object_address.sql +++ b/src/test/regress/sql/object_address.sql @@ -282,7 +282,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace -- 2.34.1 --gtUR827Uq8d5gVsQ-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v3] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-23 09:27 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-23 09:27 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing them to hit the default case and error out with "unsupported object class". During DROP PROPERTY GRAPH, this manifests when an event trigger is active, because pg_event_trigger_ddl_commands() calls these functions. The same code paths are also reachable via pg_identify_object() and pg_identify_object_as_address(). This commit adds the missing cases. Test coverage is added in object_address.sql for these two catalog types and in create_property_graph.sql covering all property graph object types. A test in event_trigger.sql verifies that DROP PROPERTY GRAPH works correctly when an event trigger is active. Author: Bertrand Drouvot <[email protected]> Reviewed-by: Michael Paquier <[email protected]> Reviewed-by: Ashutosh Bapat <[email protected]> Discussion: https://postgr.es/m/aej1DkLwhyZWmtxJ@bdtpg --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 78 ++++++++++++++++ src/test/regress/expected/event_trigger.out | 17 ++++ src/test/regress/expected/object_address.out | 10 +- .../regress/sql/create_property_graph.sql | 23 +++++ src/test/regress/sql/event_trigger.sql | 13 +++ src/test/regress/sql/object_address.sql | 6 +- 7 files changed, 238 insertions(+), 2 deletions(-) 14.7% src/backend/catalog/ 75.5% src/test/regress/expected/ 9.7% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..eb9e17fb727 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -752,6 +752,84 @@ SELECT (pg_identify_object(classid, objid, objsubid)).* type | create_property_graph_tests | g2 | create_property_graph_tests.g2 (21 rows) +-- test object address functions with recursive dependency walk +-- covers all property graph object types including indirect dependents +SELECT * +FROM ( + WITH RECURSIVE deps (classid, objid, objsubid, refclassid, refobjid, refobjsubid) AS ( + SELECT classid, objid, objsubid, + refclassid, refobjid, refobjsubid + FROM pg_depend + WHERE refclassid = 'pg_class'::regclass AND + refobjid = 'create_property_graph_tests.gt'::regclass + UNION ALL + SELECT d.classid, d.objid, d.objsubid, + d.refclassid, d.refobjid, d.refobjsubid + FROM pg_depend d + JOIN deps dp ON d.refclassid = dp.classid AND d.refobjid = dp.objid AND d.refobjsubid = dp.objsubid + ) + SELECT pg_describe_object(classid, objid, objsubid) as obj, + pg_identify_object(classid, objid, objsubid) as ident, + pg_identify_object_as_address(classid, objid, objsubid) as addr + FROM deps +) s +ORDER BY obj COLLATE "C", ident::text COLLATE "C"; + obj | ident | addr +----------------------------------------------------------+----------------------------------------------------------------------------+---------------------------------------------------------------------------- + edge e of property graph gt | ("property graph element",,,"e of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,e}",{}) + edge e of property graph gt | ("property graph element",,,"e of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,e}",{}) + edge e of property graph gt | ("property graph element",,,"e of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of property graph gt | ("property graph label",,,"e of create_property_graph_tests.gt") | ("property graph label","{create_property_graph_tests,gt,e}",{}) + label v1 of property graph gt | ("property graph label",,,"v1 of create_property_graph_tests.gt") | ("property graph label","{create_property_graph_tests,gt,v1}",{}) + label v1 of vertex v1 of property graph gt | ("property graph element label",,,"v1 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v1}",{}) + label v1 of vertex v1 of property graph gt | ("property graph element label",,,"v1 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v1}",{}) + label v2 of property graph gt | ("property graph label",,,"v2 of create_property_graph_tests.gt") | ("property graph label","{create_property_graph_tests,gt,v2}",{}) + label v2 of vertex v2 of property graph gt | ("property graph element label",,,"v2 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v2}",{}) + label v2 of vertex v2 of property graph gt | ("property graph element label",,,"v2 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v2}",{}) + property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property a of property graph gt | ("property graph property",,,"a of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,a}",{}) + property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property b of property graph gt | ("property graph property",,,"b of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,b}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of property graph gt | ("property graph property",,,"c of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,c}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of property graph gt | ("property graph property",,,"k1 of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,k1}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of property graph gt | ("property graph property",,,"k2 of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,k2}",{}) + property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property m of property graph gt | ("property graph property",,,"m of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,m}",{}) + property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property n of property graph gt | ("property graph property",,,"n of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,n}",{}) + type gt | (type,create_property_graph_tests,gt,create_property_graph_tests.gt) | (type,{create_property_graph_tests.gt},{}) + type gt[] | (type,create_property_graph_tests,_gt,create_property_graph_tests.gt[]) | (type,{create_property_graph_tests.gt[]},{}) + vertex v1 of property graph gt | ("property graph element",,,"v1 of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,v1}",{}) + vertex v2 of property graph gt | ("property graph element",,,"v2 of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,v2}",{}) +(52 rows) + \a\t SELECT pg_get_propgraphdef('g2'::regclass); CREATE PROPERTY GRAPH create_property_graph_tests.g2 diff --git a/src/test/regress/expected/event_trigger.out b/src/test/regress/expected/event_trigger.out index 065f586310f..ed8d5df397e 100644 --- a/src/test/regress/expected/event_trigger.out +++ b/src/test/regress/expected/event_trigger.out @@ -173,6 +173,23 @@ NOTICE: test_event_trigger: ddl_command_end CREATE USER MAPPING alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; NOTICE: test_event_trigger: ddl_command_end ALTER DEFAULT PRIVILEGES +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE TABLE t2x (i int PRIMARY KEY, j text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); +NOTICE: test_event_trigger: ddl_command_end CREATE PROPERTY GRAPH +DROP PROPERTY GRAPH gx; +NOTICE: test_event_trigger: ddl_command_end DROP PROPERTY GRAPH +DROP TABLE t1x, t2x; +NOTICE: test_event_trigger: ddl_command_end DROP TABLE -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; ERROR: permission denied to change owner of event trigger "regress_event_trigger" diff --git a/src/test/regress/expected/object_address.out b/src/test/regress/expected/object_address.out index 97227d67a54..5e53f0b092e 100644 --- a/src/test/regress/expected/object_address.out +++ b/src/test/regress/expected/object_address.out @@ -67,7 +67,9 @@ DECLARE BEGIN FOR objtype IN VALUES ('toast table'), ('index column'), ('sequence column'), ('toast table column'), ('view column'), ('materialized view column'), - ('property graph element'), ('property graph label'), ('property graph property') + ('property graph element'), ('property graph element label'), + ('property graph label'), ('property graph label property'), + ('property graph property') LOOP BEGIN PERFORM pg_get_object_address(objtype, '{one}', '{}'); @@ -84,7 +86,9 @@ WARNING: error for toast table column: unsupported object type "toast table col WARNING: error for view column: unsupported object type "view column" WARNING: error for materialized view column: unsupported object type "materialized view column" WARNING: error for property graph element: unsupported object type "property graph element" +WARNING: error for property graph element label: unrecognized object type "property graph element label" WARNING: error for property graph label: unsupported object type "property graph label" +WARNING: error for property graph label property: unrecognized object type "property graph label property" WARNING: error for property graph property: unsupported object type "property graph property" -- miscellaneous other errors select * from pg_get_object_address('operator of access method', '{btree,integer_ops,1}', '{int4,bool}'); @@ -593,7 +597,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace @@ -653,6 +659,8 @@ ORDER BY objects.classid, objects.objid, objects.objsubid; ("(""parameter ACL"",,,)")|("(""parameter ACL"",,)")|NULL ("(""property graph element"",,,)")|("(""property graph element"",,)")|NULL ("(""property graph label"",,,)")|("(""property graph label"",,)")|NULL +("(""property graph element label"",,,)")|("(""property graph element label"",,)")|NULL ("(""property graph property"",,,)")|("(""property graph property"",,)")|NULL +("(""property graph label property"",,,)")|("(""property graph label property"",,)")|NULL -- restore normal output mode \a\t diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..9608dd5c4af 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -298,6 +298,29 @@ SELECT (pg_identify_object(classid, objid, objsubid)).* refobjid = 'create_property_graph_tests.g2'::regclass ORDER BY 1, 2, 3, 4; +-- test object address functions with recursive dependency walk +-- covers all property graph object types including indirect dependents +SELECT * +FROM ( + WITH RECURSIVE deps (classid, objid, objsubid, refclassid, refobjid, refobjsubid) AS ( + SELECT classid, objid, objsubid, + refclassid, refobjid, refobjsubid + FROM pg_depend + WHERE refclassid = 'pg_class'::regclass AND + refobjid = 'create_property_graph_tests.gt'::regclass + UNION ALL + SELECT d.classid, d.objid, d.objsubid, + d.refclassid, d.refobjid, d.refobjsubid + FROM pg_depend d + JOIN deps dp ON d.refclassid = dp.classid AND d.refobjid = dp.objid AND d.refobjsubid = dp.objsubid + ) + SELECT pg_describe_object(classid, objid, objsubid) as obj, + pg_identify_object(classid, objid, objsubid) as ident, + pg_identify_object_as_address(classid, objid, objsubid) as addr + FROM deps +) s +ORDER BY obj COLLATE "C", ident::text COLLATE "C"; + \a\t SELECT pg_get_propgraphdef('g2'::regclass); SELECT pg_get_propgraphdef('g3'::regclass); diff --git a/src/test/regress/sql/event_trigger.sql b/src/test/regress/sql/event_trigger.sql index 32e9bb58c5e..271f443378b 100644 --- a/src/test/regress/sql/event_trigger.sql +++ b/src/test/regress/sql/event_trigger.sql @@ -143,6 +143,19 @@ create user mapping for regress_evt_user server useless_server; alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +CREATE TABLE t2x (i int PRIMARY KEY, j text); + +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); + +DROP PROPERTY GRAPH gx; +DROP TABLE t1x, t2x; + -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; diff --git a/src/test/regress/sql/object_address.sql b/src/test/regress/sql/object_address.sql index 1bbe9457c1c..27109d421c7 100644 --- a/src/test/regress/sql/object_address.sql +++ b/src/test/regress/sql/object_address.sql @@ -67,7 +67,9 @@ DECLARE BEGIN FOR objtype IN VALUES ('toast table'), ('index column'), ('sequence column'), ('toast table column'), ('view column'), ('materialized view column'), - ('property graph element'), ('property graph label'), ('property graph property') + ('property graph element'), ('property graph element label'), + ('property graph label'), ('property graph label property'), + ('property graph property') LOOP BEGIN PERFORM pg_get_object_address(objtype, '{one}', '{}'); @@ -282,7 +284,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace -- 2.34.1 --R84XrR4Hgw0dH3Ec-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v3] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-23 09:27 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-23 09:27 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing them to hit the default case and error out with "unsupported object class". During DROP PROPERTY GRAPH, this manifests when an event trigger is active, because pg_event_trigger_ddl_commands() calls these functions. The same code paths are also reachable via pg_identify_object() and pg_identify_object_as_address(). This commit adds the missing cases. Test coverage is added in object_address.sql for these two catalog types and in create_property_graph.sql covering all property graph object types. A test in event_trigger.sql verifies that DROP PROPERTY GRAPH works correctly when an event trigger is active. Author: Bertrand Drouvot <[email protected]> Reviewed-by: Michael Paquier <[email protected]> Reviewed-by: Ashutosh Bapat <[email protected]> Discussion: https://postgr.es/m/aej1DkLwhyZWmtxJ@bdtpg --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 78 ++++++++++++++++ src/test/regress/expected/event_trigger.out | 17 ++++ src/test/regress/expected/object_address.out | 10 +- .../regress/sql/create_property_graph.sql | 23 +++++ src/test/regress/sql/event_trigger.sql | 13 +++ src/test/regress/sql/object_address.sql | 6 +- 7 files changed, 238 insertions(+), 2 deletions(-) 14.7% src/backend/catalog/ 75.5% src/test/regress/expected/ 9.7% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..eb9e17fb727 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -752,6 +752,84 @@ SELECT (pg_identify_object(classid, objid, objsubid)).* type | create_property_graph_tests | g2 | create_property_graph_tests.g2 (21 rows) +-- test object address functions with recursive dependency walk +-- covers all property graph object types including indirect dependents +SELECT * +FROM ( + WITH RECURSIVE deps (classid, objid, objsubid, refclassid, refobjid, refobjsubid) AS ( + SELECT classid, objid, objsubid, + refclassid, refobjid, refobjsubid + FROM pg_depend + WHERE refclassid = 'pg_class'::regclass AND + refobjid = 'create_property_graph_tests.gt'::regclass + UNION ALL + SELECT d.classid, d.objid, d.objsubid, + d.refclassid, d.refobjid, d.refobjsubid + FROM pg_depend d + JOIN deps dp ON d.refclassid = dp.classid AND d.refobjid = dp.objid AND d.refobjsubid = dp.objsubid + ) + SELECT pg_describe_object(classid, objid, objsubid) as obj, + pg_identify_object(classid, objid, objsubid) as ident, + pg_identify_object_as_address(classid, objid, objsubid) as addr + FROM deps +) s +ORDER BY obj COLLATE "C", ident::text COLLATE "C"; + obj | ident | addr +----------------------------------------------------------+----------------------------------------------------------------------------+---------------------------------------------------------------------------- + edge e of property graph gt | ("property graph element",,,"e of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,e}",{}) + edge e of property graph gt | ("property graph element",,,"e of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,e}",{}) + edge e of property graph gt | ("property graph element",,,"e of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of property graph gt | ("property graph label",,,"e of create_property_graph_tests.gt") | ("property graph label","{create_property_graph_tests,gt,e}",{}) + label v1 of property graph gt | ("property graph label",,,"v1 of create_property_graph_tests.gt") | ("property graph label","{create_property_graph_tests,gt,v1}",{}) + label v1 of vertex v1 of property graph gt | ("property graph element label",,,"v1 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v1}",{}) + label v1 of vertex v1 of property graph gt | ("property graph element label",,,"v1 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v1}",{}) + label v2 of property graph gt | ("property graph label",,,"v2 of create_property_graph_tests.gt") | ("property graph label","{create_property_graph_tests,gt,v2}",{}) + label v2 of vertex v2 of property graph gt | ("property graph element label",,,"v2 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v2}",{}) + label v2 of vertex v2 of property graph gt | ("property graph element label",,,"v2 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v2}",{}) + property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property a of property graph gt | ("property graph property",,,"a of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,a}",{}) + property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property b of property graph gt | ("property graph property",,,"b of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,b}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of property graph gt | ("property graph property",,,"c of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,c}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of property graph gt | ("property graph property",,,"k1 of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,k1}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of property graph gt | ("property graph property",,,"k2 of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,k2}",{}) + property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property m of property graph gt | ("property graph property",,,"m of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,m}",{}) + property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property n of property graph gt | ("property graph property",,,"n of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,n}",{}) + type gt | (type,create_property_graph_tests,gt,create_property_graph_tests.gt) | (type,{create_property_graph_tests.gt},{}) + type gt[] | (type,create_property_graph_tests,_gt,create_property_graph_tests.gt[]) | (type,{create_property_graph_tests.gt[]},{}) + vertex v1 of property graph gt | ("property graph element",,,"v1 of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,v1}",{}) + vertex v2 of property graph gt | ("property graph element",,,"v2 of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,v2}",{}) +(52 rows) + \a\t SELECT pg_get_propgraphdef('g2'::regclass); CREATE PROPERTY GRAPH create_property_graph_tests.g2 diff --git a/src/test/regress/expected/event_trigger.out b/src/test/regress/expected/event_trigger.out index 065f586310f..ed8d5df397e 100644 --- a/src/test/regress/expected/event_trigger.out +++ b/src/test/regress/expected/event_trigger.out @@ -173,6 +173,23 @@ NOTICE: test_event_trigger: ddl_command_end CREATE USER MAPPING alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; NOTICE: test_event_trigger: ddl_command_end ALTER DEFAULT PRIVILEGES +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE TABLE t2x (i int PRIMARY KEY, j text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); +NOTICE: test_event_trigger: ddl_command_end CREATE PROPERTY GRAPH +DROP PROPERTY GRAPH gx; +NOTICE: test_event_trigger: ddl_command_end DROP PROPERTY GRAPH +DROP TABLE t1x, t2x; +NOTICE: test_event_trigger: ddl_command_end DROP TABLE -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; ERROR: permission denied to change owner of event trigger "regress_event_trigger" diff --git a/src/test/regress/expected/object_address.out b/src/test/regress/expected/object_address.out index 97227d67a54..5e53f0b092e 100644 --- a/src/test/regress/expected/object_address.out +++ b/src/test/regress/expected/object_address.out @@ -67,7 +67,9 @@ DECLARE BEGIN FOR objtype IN VALUES ('toast table'), ('index column'), ('sequence column'), ('toast table column'), ('view column'), ('materialized view column'), - ('property graph element'), ('property graph label'), ('property graph property') + ('property graph element'), ('property graph element label'), + ('property graph label'), ('property graph label property'), + ('property graph property') LOOP BEGIN PERFORM pg_get_object_address(objtype, '{one}', '{}'); @@ -84,7 +86,9 @@ WARNING: error for toast table column: unsupported object type "toast table col WARNING: error for view column: unsupported object type "view column" WARNING: error for materialized view column: unsupported object type "materialized view column" WARNING: error for property graph element: unsupported object type "property graph element" +WARNING: error for property graph element label: unrecognized object type "property graph element label" WARNING: error for property graph label: unsupported object type "property graph label" +WARNING: error for property graph label property: unrecognized object type "property graph label property" WARNING: error for property graph property: unsupported object type "property graph property" -- miscellaneous other errors select * from pg_get_object_address('operator of access method', '{btree,integer_ops,1}', '{int4,bool}'); @@ -593,7 +597,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace @@ -653,6 +659,8 @@ ORDER BY objects.classid, objects.objid, objects.objsubid; ("(""parameter ACL"",,,)")|("(""parameter ACL"",,)")|NULL ("(""property graph element"",,,)")|("(""property graph element"",,)")|NULL ("(""property graph label"",,,)")|("(""property graph label"",,)")|NULL +("(""property graph element label"",,,)")|("(""property graph element label"",,)")|NULL ("(""property graph property"",,,)")|("(""property graph property"",,)")|NULL +("(""property graph label property"",,,)")|("(""property graph label property"",,)")|NULL -- restore normal output mode \a\t diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..9608dd5c4af 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -298,6 +298,29 @@ SELECT (pg_identify_object(classid, objid, objsubid)).* refobjid = 'create_property_graph_tests.g2'::regclass ORDER BY 1, 2, 3, 4; +-- test object address functions with recursive dependency walk +-- covers all property graph object types including indirect dependents +SELECT * +FROM ( + WITH RECURSIVE deps (classid, objid, objsubid, refclassid, refobjid, refobjsubid) AS ( + SELECT classid, objid, objsubid, + refclassid, refobjid, refobjsubid + FROM pg_depend + WHERE refclassid = 'pg_class'::regclass AND + refobjid = 'create_property_graph_tests.gt'::regclass + UNION ALL + SELECT d.classid, d.objid, d.objsubid, + d.refclassid, d.refobjid, d.refobjsubid + FROM pg_depend d + JOIN deps dp ON d.refclassid = dp.classid AND d.refobjid = dp.objid AND d.refobjsubid = dp.objsubid + ) + SELECT pg_describe_object(classid, objid, objsubid) as obj, + pg_identify_object(classid, objid, objsubid) as ident, + pg_identify_object_as_address(classid, objid, objsubid) as addr + FROM deps +) s +ORDER BY obj COLLATE "C", ident::text COLLATE "C"; + \a\t SELECT pg_get_propgraphdef('g2'::regclass); SELECT pg_get_propgraphdef('g3'::regclass); diff --git a/src/test/regress/sql/event_trigger.sql b/src/test/regress/sql/event_trigger.sql index 32e9bb58c5e..271f443378b 100644 --- a/src/test/regress/sql/event_trigger.sql +++ b/src/test/regress/sql/event_trigger.sql @@ -143,6 +143,19 @@ create user mapping for regress_evt_user server useless_server; alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +CREATE TABLE t2x (i int PRIMARY KEY, j text); + +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); + +DROP PROPERTY GRAPH gx; +DROP TABLE t1x, t2x; + -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; diff --git a/src/test/regress/sql/object_address.sql b/src/test/regress/sql/object_address.sql index 1bbe9457c1c..27109d421c7 100644 --- a/src/test/regress/sql/object_address.sql +++ b/src/test/regress/sql/object_address.sql @@ -67,7 +67,9 @@ DECLARE BEGIN FOR objtype IN VALUES ('toast table'), ('index column'), ('sequence column'), ('toast table column'), ('view column'), ('materialized view column'), - ('property graph element'), ('property graph label'), ('property graph property') + ('property graph element'), ('property graph element label'), + ('property graph label'), ('property graph label property'), + ('property graph property') LOOP BEGIN PERFORM pg_get_object_address(objtype, '{one}', '{}'); @@ -282,7 +284,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace -- 2.34.1 --R84XrR4Hgw0dH3Ec-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v3] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-23 09:27 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-23 09:27 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing them to hit the default case and error out with "unsupported object class". During DROP PROPERTY GRAPH, this manifests when an event trigger is active, because pg_event_trigger_ddl_commands() calls these functions. The same code paths are also reachable via pg_identify_object() and pg_identify_object_as_address(). This commit adds the missing cases. Test coverage is added in object_address.sql for these two catalog types and in create_property_graph.sql covering all property graph object types. A test in event_trigger.sql verifies that DROP PROPERTY GRAPH works correctly when an event trigger is active. Author: Bertrand Drouvot <[email protected]> Reviewed-by: Michael Paquier <[email protected]> Reviewed-by: Ashutosh Bapat <[email protected]> Discussion: https://postgr.es/m/aej1DkLwhyZWmtxJ@bdtpg --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 78 ++++++++++++++++ src/test/regress/expected/event_trigger.out | 17 ++++ src/test/regress/expected/object_address.out | 10 +- .../regress/sql/create_property_graph.sql | 23 +++++ src/test/regress/sql/event_trigger.sql | 13 +++ src/test/regress/sql/object_address.sql | 6 +- 7 files changed, 238 insertions(+), 2 deletions(-) 14.7% src/backend/catalog/ 75.5% src/test/regress/expected/ 9.7% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..eb9e17fb727 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -752,6 +752,84 @@ SELECT (pg_identify_object(classid, objid, objsubid)).* type | create_property_graph_tests | g2 | create_property_graph_tests.g2 (21 rows) +-- test object address functions with recursive dependency walk +-- covers all property graph object types including indirect dependents +SELECT * +FROM ( + WITH RECURSIVE deps (classid, objid, objsubid, refclassid, refobjid, refobjsubid) AS ( + SELECT classid, objid, objsubid, + refclassid, refobjid, refobjsubid + FROM pg_depend + WHERE refclassid = 'pg_class'::regclass AND + refobjid = 'create_property_graph_tests.gt'::regclass + UNION ALL + SELECT d.classid, d.objid, d.objsubid, + d.refclassid, d.refobjid, d.refobjsubid + FROM pg_depend d + JOIN deps dp ON d.refclassid = dp.classid AND d.refobjid = dp.objid AND d.refobjsubid = dp.objsubid + ) + SELECT pg_describe_object(classid, objid, objsubid) as obj, + pg_identify_object(classid, objid, objsubid) as ident, + pg_identify_object_as_address(classid, objid, objsubid) as addr + FROM deps +) s +ORDER BY obj COLLATE "C", ident::text COLLATE "C"; + obj | ident | addr +----------------------------------------------------------+----------------------------------------------------------------------------+---------------------------------------------------------------------------- + edge e of property graph gt | ("property graph element",,,"e of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,e}",{}) + edge e of property graph gt | ("property graph element",,,"e of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,e}",{}) + edge e of property graph gt | ("property graph element",,,"e of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of property graph gt | ("property graph label",,,"e of create_property_graph_tests.gt") | ("property graph label","{create_property_graph_tests,gt,e}",{}) + label v1 of property graph gt | ("property graph label",,,"v1 of create_property_graph_tests.gt") | ("property graph label","{create_property_graph_tests,gt,v1}",{}) + label v1 of vertex v1 of property graph gt | ("property graph element label",,,"v1 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v1}",{}) + label v1 of vertex v1 of property graph gt | ("property graph element label",,,"v1 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v1}",{}) + label v2 of property graph gt | ("property graph label",,,"v2 of create_property_graph_tests.gt") | ("property graph label","{create_property_graph_tests,gt,v2}",{}) + label v2 of vertex v2 of property graph gt | ("property graph element label",,,"v2 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v2}",{}) + label v2 of vertex v2 of property graph gt | ("property graph element label",,,"v2 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v2}",{}) + property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property a of property graph gt | ("property graph property",,,"a of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,a}",{}) + property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property b of property graph gt | ("property graph property",,,"b of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,b}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of property graph gt | ("property graph property",,,"c of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,c}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of property graph gt | ("property graph property",,,"k1 of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,k1}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of property graph gt | ("property graph property",,,"k2 of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,k2}",{}) + property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property m of property graph gt | ("property graph property",,,"m of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,m}",{}) + property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property n of property graph gt | ("property graph property",,,"n of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,n}",{}) + type gt | (type,create_property_graph_tests,gt,create_property_graph_tests.gt) | (type,{create_property_graph_tests.gt},{}) + type gt[] | (type,create_property_graph_tests,_gt,create_property_graph_tests.gt[]) | (type,{create_property_graph_tests.gt[]},{}) + vertex v1 of property graph gt | ("property graph element",,,"v1 of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,v1}",{}) + vertex v2 of property graph gt | ("property graph element",,,"v2 of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,v2}",{}) +(52 rows) + \a\t SELECT pg_get_propgraphdef('g2'::regclass); CREATE PROPERTY GRAPH create_property_graph_tests.g2 diff --git a/src/test/regress/expected/event_trigger.out b/src/test/regress/expected/event_trigger.out index 065f586310f..ed8d5df397e 100644 --- a/src/test/regress/expected/event_trigger.out +++ b/src/test/regress/expected/event_trigger.out @@ -173,6 +173,23 @@ NOTICE: test_event_trigger: ddl_command_end CREATE USER MAPPING alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; NOTICE: test_event_trigger: ddl_command_end ALTER DEFAULT PRIVILEGES +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE TABLE t2x (i int PRIMARY KEY, j text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); +NOTICE: test_event_trigger: ddl_command_end CREATE PROPERTY GRAPH +DROP PROPERTY GRAPH gx; +NOTICE: test_event_trigger: ddl_command_end DROP PROPERTY GRAPH +DROP TABLE t1x, t2x; +NOTICE: test_event_trigger: ddl_command_end DROP TABLE -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; ERROR: permission denied to change owner of event trigger "regress_event_trigger" diff --git a/src/test/regress/expected/object_address.out b/src/test/regress/expected/object_address.out index 97227d67a54..5e53f0b092e 100644 --- a/src/test/regress/expected/object_address.out +++ b/src/test/regress/expected/object_address.out @@ -67,7 +67,9 @@ DECLARE BEGIN FOR objtype IN VALUES ('toast table'), ('index column'), ('sequence column'), ('toast table column'), ('view column'), ('materialized view column'), - ('property graph element'), ('property graph label'), ('property graph property') + ('property graph element'), ('property graph element label'), + ('property graph label'), ('property graph label property'), + ('property graph property') LOOP BEGIN PERFORM pg_get_object_address(objtype, '{one}', '{}'); @@ -84,7 +86,9 @@ WARNING: error for toast table column: unsupported object type "toast table col WARNING: error for view column: unsupported object type "view column" WARNING: error for materialized view column: unsupported object type "materialized view column" WARNING: error for property graph element: unsupported object type "property graph element" +WARNING: error for property graph element label: unrecognized object type "property graph element label" WARNING: error for property graph label: unsupported object type "property graph label" +WARNING: error for property graph label property: unrecognized object type "property graph label property" WARNING: error for property graph property: unsupported object type "property graph property" -- miscellaneous other errors select * from pg_get_object_address('operator of access method', '{btree,integer_ops,1}', '{int4,bool}'); @@ -593,7 +597,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace @@ -653,6 +659,8 @@ ORDER BY objects.classid, objects.objid, objects.objsubid; ("(""parameter ACL"",,,)")|("(""parameter ACL"",,)")|NULL ("(""property graph element"",,,)")|("(""property graph element"",,)")|NULL ("(""property graph label"",,,)")|("(""property graph label"",,)")|NULL +("(""property graph element label"",,,)")|("(""property graph element label"",,)")|NULL ("(""property graph property"",,,)")|("(""property graph property"",,)")|NULL +("(""property graph label property"",,,)")|("(""property graph label property"",,)")|NULL -- restore normal output mode \a\t diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..9608dd5c4af 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -298,6 +298,29 @@ SELECT (pg_identify_object(classid, objid, objsubid)).* refobjid = 'create_property_graph_tests.g2'::regclass ORDER BY 1, 2, 3, 4; +-- test object address functions with recursive dependency walk +-- covers all property graph object types including indirect dependents +SELECT * +FROM ( + WITH RECURSIVE deps (classid, objid, objsubid, refclassid, refobjid, refobjsubid) AS ( + SELECT classid, objid, objsubid, + refclassid, refobjid, refobjsubid + FROM pg_depend + WHERE refclassid = 'pg_class'::regclass AND + refobjid = 'create_property_graph_tests.gt'::regclass + UNION ALL + SELECT d.classid, d.objid, d.objsubid, + d.refclassid, d.refobjid, d.refobjsubid + FROM pg_depend d + JOIN deps dp ON d.refclassid = dp.classid AND d.refobjid = dp.objid AND d.refobjsubid = dp.objsubid + ) + SELECT pg_describe_object(classid, objid, objsubid) as obj, + pg_identify_object(classid, objid, objsubid) as ident, + pg_identify_object_as_address(classid, objid, objsubid) as addr + FROM deps +) s +ORDER BY obj COLLATE "C", ident::text COLLATE "C"; + \a\t SELECT pg_get_propgraphdef('g2'::regclass); SELECT pg_get_propgraphdef('g3'::regclass); diff --git a/src/test/regress/sql/event_trigger.sql b/src/test/regress/sql/event_trigger.sql index 32e9bb58c5e..271f443378b 100644 --- a/src/test/regress/sql/event_trigger.sql +++ b/src/test/regress/sql/event_trigger.sql @@ -143,6 +143,19 @@ create user mapping for regress_evt_user server useless_server; alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +CREATE TABLE t2x (i int PRIMARY KEY, j text); + +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); + +DROP PROPERTY GRAPH gx; +DROP TABLE t1x, t2x; + -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; diff --git a/src/test/regress/sql/object_address.sql b/src/test/regress/sql/object_address.sql index 1bbe9457c1c..27109d421c7 100644 --- a/src/test/regress/sql/object_address.sql +++ b/src/test/regress/sql/object_address.sql @@ -67,7 +67,9 @@ DECLARE BEGIN FOR objtype IN VALUES ('toast table'), ('index column'), ('sequence column'), ('toast table column'), ('view column'), ('materialized view column'), - ('property graph element'), ('property graph label'), ('property graph property') + ('property graph element'), ('property graph element label'), + ('property graph label'), ('property graph label property'), + ('property graph property') LOOP BEGIN PERFORM pg_get_object_address(objtype, '{one}', '{}'); @@ -282,7 +284,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace -- 2.34.1 --R84XrR4Hgw0dH3Ec-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v2] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-23 09:27 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-23 09:27 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing them to hit the default case and error out with "unsupported object class". During DROP PROPERTY GRAPH, this manifests when an event trigger is active, because pg_event_trigger_ddl_commands() calls these functions. The same code paths are also reachable via pg_identify_object() and pg_identify_object_as_address(). This commit adds the missing cases. Test coverage is added in object_address.sql for these two catalog types via the zero-OID test that exercises pg_identify_object() and pg_identify_object_as_address(). A test in event_trigger.sql verifies that DROP PROPERTY GRAPH works correctly when an event trigger is active. Author: Bertrand Drouvot <[email protected]> Reviewed-by: Michael Paquier <[email protected]> Reviewed-by: Ashutosh Bapat <[email protected]> Discussion: https://postgr.es/m/aej1DkLwhyZWmtxJ@bdtpg --- src/backend/catalog/objectaddress.c | 93 ++++++++++++++++++++ src/test/regress/expected/event_trigger.out | 17 ++++ src/test/regress/expected/object_address.out | 4 + src/test/regress/sql/event_trigger.sql | 13 +++ src/test/regress/sql/object_address.sql | 2 + 5 files changed, 129 insertions(+) 62.4% src/backend/catalog/ 25.6% src/test/regress/expected/ 11.8% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/event_trigger.out b/src/test/regress/expected/event_trigger.out index 065f586310f..ed8d5df397e 100644 --- a/src/test/regress/expected/event_trigger.out +++ b/src/test/regress/expected/event_trigger.out @@ -173,6 +173,23 @@ NOTICE: test_event_trigger: ddl_command_end CREATE USER MAPPING alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; NOTICE: test_event_trigger: ddl_command_end ALTER DEFAULT PRIVILEGES +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE TABLE t2x (i int PRIMARY KEY, j text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); +NOTICE: test_event_trigger: ddl_command_end CREATE PROPERTY GRAPH +DROP PROPERTY GRAPH gx; +NOTICE: test_event_trigger: ddl_command_end DROP PROPERTY GRAPH +DROP TABLE t1x, t2x; +NOTICE: test_event_trigger: ddl_command_end DROP TABLE -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; ERROR: permission denied to change owner of event trigger "regress_event_trigger" diff --git a/src/test/regress/expected/object_address.out b/src/test/regress/expected/object_address.out index 97227d67a54..729c3537f25 100644 --- a/src/test/regress/expected/object_address.out +++ b/src/test/regress/expected/object_address.out @@ -593,7 +593,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace @@ -653,6 +655,8 @@ ORDER BY objects.classid, objects.objid, objects.objsubid; ("(""parameter ACL"",,,)")|("(""parameter ACL"",,)")|NULL ("(""property graph element"",,,)")|("(""property graph element"",,)")|NULL ("(""property graph label"",,,)")|("(""property graph label"",,)")|NULL +("(""property graph element label"",,,)")|("(""property graph element label"",,)")|NULL ("(""property graph property"",,,)")|("(""property graph property"",,)")|NULL +("(""property graph label property"",,,)")|("(""property graph label property"",,)")|NULL -- restore normal output mode \a\t diff --git a/src/test/regress/sql/event_trigger.sql b/src/test/regress/sql/event_trigger.sql index 32e9bb58c5e..271f443378b 100644 --- a/src/test/regress/sql/event_trigger.sql +++ b/src/test/regress/sql/event_trigger.sql @@ -143,6 +143,19 @@ create user mapping for regress_evt_user server useless_server; alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +CREATE TABLE t2x (i int PRIMARY KEY, j text); + +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); + +DROP PROPERTY GRAPH gx; +DROP TABLE t1x, t2x; + -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; diff --git a/src/test/regress/sql/object_address.sql b/src/test/regress/sql/object_address.sql index 1bbe9457c1c..620dacf1045 100644 --- a/src/test/regress/sql/object_address.sql +++ b/src/test/regress/sql/object_address.sql @@ -282,7 +282,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace -- 2.34.1 --gtUR827Uq8d5gVsQ-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v3] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-23 09:27 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-23 09:27 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing them to hit the default case and error out with "unsupported object class". During DROP PROPERTY GRAPH, this manifests when an event trigger is active, because pg_event_trigger_ddl_commands() calls these functions. The same code paths are also reachable via pg_identify_object() and pg_identify_object_as_address(). This commit adds the missing cases. Test coverage is added in object_address.sql for these two catalog types and in create_property_graph.sql covering all property graph object types. A test in event_trigger.sql verifies that DROP PROPERTY GRAPH works correctly when an event trigger is active. Author: Bertrand Drouvot <[email protected]> Reviewed-by: Michael Paquier <[email protected]> Reviewed-by: Ashutosh Bapat <[email protected]> Discussion: https://postgr.es/m/aej1DkLwhyZWmtxJ@bdtpg --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 78 ++++++++++++++++ src/test/regress/expected/event_trigger.out | 17 ++++ src/test/regress/expected/object_address.out | 10 +- .../regress/sql/create_property_graph.sql | 23 +++++ src/test/regress/sql/event_trigger.sql | 13 +++ src/test/regress/sql/object_address.sql | 6 +- 7 files changed, 238 insertions(+), 2 deletions(-) 14.7% src/backend/catalog/ 75.5% src/test/regress/expected/ 9.7% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..eb9e17fb727 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -752,6 +752,84 @@ SELECT (pg_identify_object(classid, objid, objsubid)).* type | create_property_graph_tests | g2 | create_property_graph_tests.g2 (21 rows) +-- test object address functions with recursive dependency walk +-- covers all property graph object types including indirect dependents +SELECT * +FROM ( + WITH RECURSIVE deps (classid, objid, objsubid, refclassid, refobjid, refobjsubid) AS ( + SELECT classid, objid, objsubid, + refclassid, refobjid, refobjsubid + FROM pg_depend + WHERE refclassid = 'pg_class'::regclass AND + refobjid = 'create_property_graph_tests.gt'::regclass + UNION ALL + SELECT d.classid, d.objid, d.objsubid, + d.refclassid, d.refobjid, d.refobjsubid + FROM pg_depend d + JOIN deps dp ON d.refclassid = dp.classid AND d.refobjid = dp.objid AND d.refobjsubid = dp.objsubid + ) + SELECT pg_describe_object(classid, objid, objsubid) as obj, + pg_identify_object(classid, objid, objsubid) as ident, + pg_identify_object_as_address(classid, objid, objsubid) as addr + FROM deps +) s +ORDER BY obj COLLATE "C", ident::text COLLATE "C"; + obj | ident | addr +----------------------------------------------------------+----------------------------------------------------------------------------+---------------------------------------------------------------------------- + edge e of property graph gt | ("property graph element",,,"e of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,e}",{}) + edge e of property graph gt | ("property graph element",,,"e of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,e}",{}) + edge e of property graph gt | ("property graph element",,,"e of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of property graph gt | ("property graph label",,,"e of create_property_graph_tests.gt") | ("property graph label","{create_property_graph_tests,gt,e}",{}) + label v1 of property graph gt | ("property graph label",,,"v1 of create_property_graph_tests.gt") | ("property graph label","{create_property_graph_tests,gt,v1}",{}) + label v1 of vertex v1 of property graph gt | ("property graph element label",,,"v1 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v1}",{}) + label v1 of vertex v1 of property graph gt | ("property graph element label",,,"v1 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v1}",{}) + label v2 of property graph gt | ("property graph label",,,"v2 of create_property_graph_tests.gt") | ("property graph label","{create_property_graph_tests,gt,v2}",{}) + label v2 of vertex v2 of property graph gt | ("property graph element label",,,"v2 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v2}",{}) + label v2 of vertex v2 of property graph gt | ("property graph element label",,,"v2 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v2}",{}) + property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property a of property graph gt | ("property graph property",,,"a of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,a}",{}) + property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property b of property graph gt | ("property graph property",,,"b of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,b}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of property graph gt | ("property graph property",,,"c of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,c}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of property graph gt | ("property graph property",,,"k1 of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,k1}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of property graph gt | ("property graph property",,,"k2 of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,k2}",{}) + property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property m of property graph gt | ("property graph property",,,"m of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,m}",{}) + property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property n of property graph gt | ("property graph property",,,"n of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,n}",{}) + type gt | (type,create_property_graph_tests,gt,create_property_graph_tests.gt) | (type,{create_property_graph_tests.gt},{}) + type gt[] | (type,create_property_graph_tests,_gt,create_property_graph_tests.gt[]) | (type,{create_property_graph_tests.gt[]},{}) + vertex v1 of property graph gt | ("property graph element",,,"v1 of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,v1}",{}) + vertex v2 of property graph gt | ("property graph element",,,"v2 of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,v2}",{}) +(52 rows) + \a\t SELECT pg_get_propgraphdef('g2'::regclass); CREATE PROPERTY GRAPH create_property_graph_tests.g2 diff --git a/src/test/regress/expected/event_trigger.out b/src/test/regress/expected/event_trigger.out index 065f586310f..ed8d5df397e 100644 --- a/src/test/regress/expected/event_trigger.out +++ b/src/test/regress/expected/event_trigger.out @@ -173,6 +173,23 @@ NOTICE: test_event_trigger: ddl_command_end CREATE USER MAPPING alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; NOTICE: test_event_trigger: ddl_command_end ALTER DEFAULT PRIVILEGES +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE TABLE t2x (i int PRIMARY KEY, j text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); +NOTICE: test_event_trigger: ddl_command_end CREATE PROPERTY GRAPH +DROP PROPERTY GRAPH gx; +NOTICE: test_event_trigger: ddl_command_end DROP PROPERTY GRAPH +DROP TABLE t1x, t2x; +NOTICE: test_event_trigger: ddl_command_end DROP TABLE -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; ERROR: permission denied to change owner of event trigger "regress_event_trigger" diff --git a/src/test/regress/expected/object_address.out b/src/test/regress/expected/object_address.out index 97227d67a54..5e53f0b092e 100644 --- a/src/test/regress/expected/object_address.out +++ b/src/test/regress/expected/object_address.out @@ -67,7 +67,9 @@ DECLARE BEGIN FOR objtype IN VALUES ('toast table'), ('index column'), ('sequence column'), ('toast table column'), ('view column'), ('materialized view column'), - ('property graph element'), ('property graph label'), ('property graph property') + ('property graph element'), ('property graph element label'), + ('property graph label'), ('property graph label property'), + ('property graph property') LOOP BEGIN PERFORM pg_get_object_address(objtype, '{one}', '{}'); @@ -84,7 +86,9 @@ WARNING: error for toast table column: unsupported object type "toast table col WARNING: error for view column: unsupported object type "view column" WARNING: error for materialized view column: unsupported object type "materialized view column" WARNING: error for property graph element: unsupported object type "property graph element" +WARNING: error for property graph element label: unrecognized object type "property graph element label" WARNING: error for property graph label: unsupported object type "property graph label" +WARNING: error for property graph label property: unrecognized object type "property graph label property" WARNING: error for property graph property: unsupported object type "property graph property" -- miscellaneous other errors select * from pg_get_object_address('operator of access method', '{btree,integer_ops,1}', '{int4,bool}'); @@ -593,7 +597,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace @@ -653,6 +659,8 @@ ORDER BY objects.classid, objects.objid, objects.objsubid; ("(""parameter ACL"",,,)")|("(""parameter ACL"",,)")|NULL ("(""property graph element"",,,)")|("(""property graph element"",,)")|NULL ("(""property graph label"",,,)")|("(""property graph label"",,)")|NULL +("(""property graph element label"",,,)")|("(""property graph element label"",,)")|NULL ("(""property graph property"",,,)")|("(""property graph property"",,)")|NULL +("(""property graph label property"",,,)")|("(""property graph label property"",,)")|NULL -- restore normal output mode \a\t diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..9608dd5c4af 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -298,6 +298,29 @@ SELECT (pg_identify_object(classid, objid, objsubid)).* refobjid = 'create_property_graph_tests.g2'::regclass ORDER BY 1, 2, 3, 4; +-- test object address functions with recursive dependency walk +-- covers all property graph object types including indirect dependents +SELECT * +FROM ( + WITH RECURSIVE deps (classid, objid, objsubid, refclassid, refobjid, refobjsubid) AS ( + SELECT classid, objid, objsubid, + refclassid, refobjid, refobjsubid + FROM pg_depend + WHERE refclassid = 'pg_class'::regclass AND + refobjid = 'create_property_graph_tests.gt'::regclass + UNION ALL + SELECT d.classid, d.objid, d.objsubid, + d.refclassid, d.refobjid, d.refobjsubid + FROM pg_depend d + JOIN deps dp ON d.refclassid = dp.classid AND d.refobjid = dp.objid AND d.refobjsubid = dp.objsubid + ) + SELECT pg_describe_object(classid, objid, objsubid) as obj, + pg_identify_object(classid, objid, objsubid) as ident, + pg_identify_object_as_address(classid, objid, objsubid) as addr + FROM deps +) s +ORDER BY obj COLLATE "C", ident::text COLLATE "C"; + \a\t SELECT pg_get_propgraphdef('g2'::regclass); SELECT pg_get_propgraphdef('g3'::regclass); diff --git a/src/test/regress/sql/event_trigger.sql b/src/test/regress/sql/event_trigger.sql index 32e9bb58c5e..271f443378b 100644 --- a/src/test/regress/sql/event_trigger.sql +++ b/src/test/regress/sql/event_trigger.sql @@ -143,6 +143,19 @@ create user mapping for regress_evt_user server useless_server; alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +CREATE TABLE t2x (i int PRIMARY KEY, j text); + +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); + +DROP PROPERTY GRAPH gx; +DROP TABLE t1x, t2x; + -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; diff --git a/src/test/regress/sql/object_address.sql b/src/test/regress/sql/object_address.sql index 1bbe9457c1c..27109d421c7 100644 --- a/src/test/regress/sql/object_address.sql +++ b/src/test/regress/sql/object_address.sql @@ -67,7 +67,9 @@ DECLARE BEGIN FOR objtype IN VALUES ('toast table'), ('index column'), ('sequence column'), ('toast table column'), ('view column'), ('materialized view column'), - ('property graph element'), ('property graph label'), ('property graph property') + ('property graph element'), ('property graph element label'), + ('property graph label'), ('property graph label property'), + ('property graph property') LOOP BEGIN PERFORM pg_get_object_address(objtype, '{one}', '{}'); @@ -282,7 +284,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace -- 2.34.1 --R84XrR4Hgw0dH3Ec-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v3] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-23 09:27 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-23 09:27 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing them to hit the default case and error out with "unsupported object class". During DROP PROPERTY GRAPH, this manifests when an event trigger is active, because pg_event_trigger_ddl_commands() calls these functions. The same code paths are also reachable via pg_identify_object() and pg_identify_object_as_address(). This commit adds the missing cases. Test coverage is added in object_address.sql for these two catalog types and in create_property_graph.sql covering all property graph object types. A test in event_trigger.sql verifies that DROP PROPERTY GRAPH works correctly when an event trigger is active. Author: Bertrand Drouvot <[email protected]> Reviewed-by: Michael Paquier <[email protected]> Reviewed-by: Ashutosh Bapat <[email protected]> Discussion: https://postgr.es/m/aej1DkLwhyZWmtxJ@bdtpg --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 78 ++++++++++++++++ src/test/regress/expected/event_trigger.out | 17 ++++ src/test/regress/expected/object_address.out | 10 +- .../regress/sql/create_property_graph.sql | 23 +++++ src/test/regress/sql/event_trigger.sql | 13 +++ src/test/regress/sql/object_address.sql | 6 +- 7 files changed, 238 insertions(+), 2 deletions(-) 14.7% src/backend/catalog/ 75.5% src/test/regress/expected/ 9.7% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..eb9e17fb727 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -752,6 +752,84 @@ SELECT (pg_identify_object(classid, objid, objsubid)).* type | create_property_graph_tests | g2 | create_property_graph_tests.g2 (21 rows) +-- test object address functions with recursive dependency walk +-- covers all property graph object types including indirect dependents +SELECT * +FROM ( + WITH RECURSIVE deps (classid, objid, objsubid, refclassid, refobjid, refobjsubid) AS ( + SELECT classid, objid, objsubid, + refclassid, refobjid, refobjsubid + FROM pg_depend + WHERE refclassid = 'pg_class'::regclass AND + refobjid = 'create_property_graph_tests.gt'::regclass + UNION ALL + SELECT d.classid, d.objid, d.objsubid, + d.refclassid, d.refobjid, d.refobjsubid + FROM pg_depend d + JOIN deps dp ON d.refclassid = dp.classid AND d.refobjid = dp.objid AND d.refobjsubid = dp.objsubid + ) + SELECT pg_describe_object(classid, objid, objsubid) as obj, + pg_identify_object(classid, objid, objsubid) as ident, + pg_identify_object_as_address(classid, objid, objsubid) as addr + FROM deps +) s +ORDER BY obj COLLATE "C", ident::text COLLATE "C"; + obj | ident | addr +----------------------------------------------------------+----------------------------------------------------------------------------+---------------------------------------------------------------------------- + edge e of property graph gt | ("property graph element",,,"e of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,e}",{}) + edge e of property graph gt | ("property graph element",,,"e of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,e}",{}) + edge e of property graph gt | ("property graph element",,,"e of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of property graph gt | ("property graph label",,,"e of create_property_graph_tests.gt") | ("property graph label","{create_property_graph_tests,gt,e}",{}) + label v1 of property graph gt | ("property graph label",,,"v1 of create_property_graph_tests.gt") | ("property graph label","{create_property_graph_tests,gt,v1}",{}) + label v1 of vertex v1 of property graph gt | ("property graph element label",,,"v1 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v1}",{}) + label v1 of vertex v1 of property graph gt | ("property graph element label",,,"v1 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v1}",{}) + label v2 of property graph gt | ("property graph label",,,"v2 of create_property_graph_tests.gt") | ("property graph label","{create_property_graph_tests,gt,v2}",{}) + label v2 of vertex v2 of property graph gt | ("property graph element label",,,"v2 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v2}",{}) + label v2 of vertex v2 of property graph gt | ("property graph element label",,,"v2 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v2}",{}) + property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property a of property graph gt | ("property graph property",,,"a of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,a}",{}) + property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property b of property graph gt | ("property graph property",,,"b of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,b}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of property graph gt | ("property graph property",,,"c of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,c}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of property graph gt | ("property graph property",,,"k1 of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,k1}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of property graph gt | ("property graph property",,,"k2 of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,k2}",{}) + property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property m of property graph gt | ("property graph property",,,"m of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,m}",{}) + property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property n of property graph gt | ("property graph property",,,"n of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,n}",{}) + type gt | (type,create_property_graph_tests,gt,create_property_graph_tests.gt) | (type,{create_property_graph_tests.gt},{}) + type gt[] | (type,create_property_graph_tests,_gt,create_property_graph_tests.gt[]) | (type,{create_property_graph_tests.gt[]},{}) + vertex v1 of property graph gt | ("property graph element",,,"v1 of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,v1}",{}) + vertex v2 of property graph gt | ("property graph element",,,"v2 of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,v2}",{}) +(52 rows) + \a\t SELECT pg_get_propgraphdef('g2'::regclass); CREATE PROPERTY GRAPH create_property_graph_tests.g2 diff --git a/src/test/regress/expected/event_trigger.out b/src/test/regress/expected/event_trigger.out index 065f586310f..ed8d5df397e 100644 --- a/src/test/regress/expected/event_trigger.out +++ b/src/test/regress/expected/event_trigger.out @@ -173,6 +173,23 @@ NOTICE: test_event_trigger: ddl_command_end CREATE USER MAPPING alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; NOTICE: test_event_trigger: ddl_command_end ALTER DEFAULT PRIVILEGES +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE TABLE t2x (i int PRIMARY KEY, j text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); +NOTICE: test_event_trigger: ddl_command_end CREATE PROPERTY GRAPH +DROP PROPERTY GRAPH gx; +NOTICE: test_event_trigger: ddl_command_end DROP PROPERTY GRAPH +DROP TABLE t1x, t2x; +NOTICE: test_event_trigger: ddl_command_end DROP TABLE -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; ERROR: permission denied to change owner of event trigger "regress_event_trigger" diff --git a/src/test/regress/expected/object_address.out b/src/test/regress/expected/object_address.out index 97227d67a54..5e53f0b092e 100644 --- a/src/test/regress/expected/object_address.out +++ b/src/test/regress/expected/object_address.out @@ -67,7 +67,9 @@ DECLARE BEGIN FOR objtype IN VALUES ('toast table'), ('index column'), ('sequence column'), ('toast table column'), ('view column'), ('materialized view column'), - ('property graph element'), ('property graph label'), ('property graph property') + ('property graph element'), ('property graph element label'), + ('property graph label'), ('property graph label property'), + ('property graph property') LOOP BEGIN PERFORM pg_get_object_address(objtype, '{one}', '{}'); @@ -84,7 +86,9 @@ WARNING: error for toast table column: unsupported object type "toast table col WARNING: error for view column: unsupported object type "view column" WARNING: error for materialized view column: unsupported object type "materialized view column" WARNING: error for property graph element: unsupported object type "property graph element" +WARNING: error for property graph element label: unrecognized object type "property graph element label" WARNING: error for property graph label: unsupported object type "property graph label" +WARNING: error for property graph label property: unrecognized object type "property graph label property" WARNING: error for property graph property: unsupported object type "property graph property" -- miscellaneous other errors select * from pg_get_object_address('operator of access method', '{btree,integer_ops,1}', '{int4,bool}'); @@ -593,7 +597,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace @@ -653,6 +659,8 @@ ORDER BY objects.classid, objects.objid, objects.objsubid; ("(""parameter ACL"",,,)")|("(""parameter ACL"",,)")|NULL ("(""property graph element"",,,)")|("(""property graph element"",,)")|NULL ("(""property graph label"",,,)")|("(""property graph label"",,)")|NULL +("(""property graph element label"",,,)")|("(""property graph element label"",,)")|NULL ("(""property graph property"",,,)")|("(""property graph property"",,)")|NULL +("(""property graph label property"",,,)")|("(""property graph label property"",,)")|NULL -- restore normal output mode \a\t diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..9608dd5c4af 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -298,6 +298,29 @@ SELECT (pg_identify_object(classid, objid, objsubid)).* refobjid = 'create_property_graph_tests.g2'::regclass ORDER BY 1, 2, 3, 4; +-- test object address functions with recursive dependency walk +-- covers all property graph object types including indirect dependents +SELECT * +FROM ( + WITH RECURSIVE deps (classid, objid, objsubid, refclassid, refobjid, refobjsubid) AS ( + SELECT classid, objid, objsubid, + refclassid, refobjid, refobjsubid + FROM pg_depend + WHERE refclassid = 'pg_class'::regclass AND + refobjid = 'create_property_graph_tests.gt'::regclass + UNION ALL + SELECT d.classid, d.objid, d.objsubid, + d.refclassid, d.refobjid, d.refobjsubid + FROM pg_depend d + JOIN deps dp ON d.refclassid = dp.classid AND d.refobjid = dp.objid AND d.refobjsubid = dp.objsubid + ) + SELECT pg_describe_object(classid, objid, objsubid) as obj, + pg_identify_object(classid, objid, objsubid) as ident, + pg_identify_object_as_address(classid, objid, objsubid) as addr + FROM deps +) s +ORDER BY obj COLLATE "C", ident::text COLLATE "C"; + \a\t SELECT pg_get_propgraphdef('g2'::regclass); SELECT pg_get_propgraphdef('g3'::regclass); diff --git a/src/test/regress/sql/event_trigger.sql b/src/test/regress/sql/event_trigger.sql index 32e9bb58c5e..271f443378b 100644 --- a/src/test/regress/sql/event_trigger.sql +++ b/src/test/regress/sql/event_trigger.sql @@ -143,6 +143,19 @@ create user mapping for regress_evt_user server useless_server; alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +CREATE TABLE t2x (i int PRIMARY KEY, j text); + +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); + +DROP PROPERTY GRAPH gx; +DROP TABLE t1x, t2x; + -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; diff --git a/src/test/regress/sql/object_address.sql b/src/test/regress/sql/object_address.sql index 1bbe9457c1c..27109d421c7 100644 --- a/src/test/regress/sql/object_address.sql +++ b/src/test/regress/sql/object_address.sql @@ -67,7 +67,9 @@ DECLARE BEGIN FOR objtype IN VALUES ('toast table'), ('index column'), ('sequence column'), ('toast table column'), ('view column'), ('materialized view column'), - ('property graph element'), ('property graph label'), ('property graph property') + ('property graph element'), ('property graph element label'), + ('property graph label'), ('property graph label property'), + ('property graph property') LOOP BEGIN PERFORM pg_get_object_address(objtype, '{one}', '{}'); @@ -282,7 +284,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace -- 2.34.1 --R84XrR4Hgw0dH3Ec-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v2] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-23 09:27 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-23 09:27 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing them to hit the default case and error out with "unsupported object class". During DROP PROPERTY GRAPH, this manifests when an event trigger is active, because pg_event_trigger_ddl_commands() calls these functions. The same code paths are also reachable via pg_identify_object() and pg_identify_object_as_address(). This commit adds the missing cases. Test coverage is added in object_address.sql for these two catalog types via the zero-OID test that exercises pg_identify_object() and pg_identify_object_as_address(). A test in event_trigger.sql verifies that DROP PROPERTY GRAPH works correctly when an event trigger is active. Author: Bertrand Drouvot <[email protected]> Reviewed-by: Michael Paquier <[email protected]> Reviewed-by: Ashutosh Bapat <[email protected]> Discussion: https://postgr.es/m/aej1DkLwhyZWmtxJ@bdtpg --- src/backend/catalog/objectaddress.c | 93 ++++++++++++++++++++ src/test/regress/expected/event_trigger.out | 17 ++++ src/test/regress/expected/object_address.out | 4 + src/test/regress/sql/event_trigger.sql | 13 +++ src/test/regress/sql/object_address.sql | 2 + 5 files changed, 129 insertions(+) 62.4% src/backend/catalog/ 25.6% src/test/regress/expected/ 11.8% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/event_trigger.out b/src/test/regress/expected/event_trigger.out index 065f586310f..ed8d5df397e 100644 --- a/src/test/regress/expected/event_trigger.out +++ b/src/test/regress/expected/event_trigger.out @@ -173,6 +173,23 @@ NOTICE: test_event_trigger: ddl_command_end CREATE USER MAPPING alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; NOTICE: test_event_trigger: ddl_command_end ALTER DEFAULT PRIVILEGES +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE TABLE t2x (i int PRIMARY KEY, j text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); +NOTICE: test_event_trigger: ddl_command_end CREATE PROPERTY GRAPH +DROP PROPERTY GRAPH gx; +NOTICE: test_event_trigger: ddl_command_end DROP PROPERTY GRAPH +DROP TABLE t1x, t2x; +NOTICE: test_event_trigger: ddl_command_end DROP TABLE -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; ERROR: permission denied to change owner of event trigger "regress_event_trigger" diff --git a/src/test/regress/expected/object_address.out b/src/test/regress/expected/object_address.out index 97227d67a54..729c3537f25 100644 --- a/src/test/regress/expected/object_address.out +++ b/src/test/regress/expected/object_address.out @@ -593,7 +593,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace @@ -653,6 +655,8 @@ ORDER BY objects.classid, objects.objid, objects.objsubid; ("(""parameter ACL"",,,)")|("(""parameter ACL"",,)")|NULL ("(""property graph element"",,,)")|("(""property graph element"",,)")|NULL ("(""property graph label"",,,)")|("(""property graph label"",,)")|NULL +("(""property graph element label"",,,)")|("(""property graph element label"",,)")|NULL ("(""property graph property"",,,)")|("(""property graph property"",,)")|NULL +("(""property graph label property"",,,)")|("(""property graph label property"",,)")|NULL -- restore normal output mode \a\t diff --git a/src/test/regress/sql/event_trigger.sql b/src/test/regress/sql/event_trigger.sql index 32e9bb58c5e..271f443378b 100644 --- a/src/test/regress/sql/event_trigger.sql +++ b/src/test/regress/sql/event_trigger.sql @@ -143,6 +143,19 @@ create user mapping for regress_evt_user server useless_server; alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +CREATE TABLE t2x (i int PRIMARY KEY, j text); + +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); + +DROP PROPERTY GRAPH gx; +DROP TABLE t1x, t2x; + -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; diff --git a/src/test/regress/sql/object_address.sql b/src/test/regress/sql/object_address.sql index 1bbe9457c1c..620dacf1045 100644 --- a/src/test/regress/sql/object_address.sql +++ b/src/test/regress/sql/object_address.sql @@ -282,7 +282,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace -- 2.34.1 --gtUR827Uq8d5gVsQ-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v3] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-23 09:27 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-23 09:27 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing them to hit the default case and error out with "unsupported object class". During DROP PROPERTY GRAPH, this manifests when an event trigger is active, because pg_event_trigger_ddl_commands() calls these functions. The same code paths are also reachable via pg_identify_object() and pg_identify_object_as_address(). This commit adds the missing cases. Test coverage is added in object_address.sql for these two catalog types and in create_property_graph.sql covering all property graph object types. A test in event_trigger.sql verifies that DROP PROPERTY GRAPH works correctly when an event trigger is active. Author: Bertrand Drouvot <[email protected]> Reviewed-by: Michael Paquier <[email protected]> Reviewed-by: Ashutosh Bapat <[email protected]> Discussion: https://postgr.es/m/aej1DkLwhyZWmtxJ@bdtpg --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 78 ++++++++++++++++ src/test/regress/expected/event_trigger.out | 17 ++++ src/test/regress/expected/object_address.out | 10 +- .../regress/sql/create_property_graph.sql | 23 +++++ src/test/regress/sql/event_trigger.sql | 13 +++ src/test/regress/sql/object_address.sql | 6 +- 7 files changed, 238 insertions(+), 2 deletions(-) 14.7% src/backend/catalog/ 75.5% src/test/regress/expected/ 9.7% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..eb9e17fb727 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -752,6 +752,84 @@ SELECT (pg_identify_object(classid, objid, objsubid)).* type | create_property_graph_tests | g2 | create_property_graph_tests.g2 (21 rows) +-- test object address functions with recursive dependency walk +-- covers all property graph object types including indirect dependents +SELECT * +FROM ( + WITH RECURSIVE deps (classid, objid, objsubid, refclassid, refobjid, refobjsubid) AS ( + SELECT classid, objid, objsubid, + refclassid, refobjid, refobjsubid + FROM pg_depend + WHERE refclassid = 'pg_class'::regclass AND + refobjid = 'create_property_graph_tests.gt'::regclass + UNION ALL + SELECT d.classid, d.objid, d.objsubid, + d.refclassid, d.refobjid, d.refobjsubid + FROM pg_depend d + JOIN deps dp ON d.refclassid = dp.classid AND d.refobjid = dp.objid AND d.refobjsubid = dp.objsubid + ) + SELECT pg_describe_object(classid, objid, objsubid) as obj, + pg_identify_object(classid, objid, objsubid) as ident, + pg_identify_object_as_address(classid, objid, objsubid) as addr + FROM deps +) s +ORDER BY obj COLLATE "C", ident::text COLLATE "C"; + obj | ident | addr +----------------------------------------------------------+----------------------------------------------------------------------------+---------------------------------------------------------------------------- + edge e of property graph gt | ("property graph element",,,"e of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,e}",{}) + edge e of property graph gt | ("property graph element",,,"e of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,e}",{}) + edge e of property graph gt | ("property graph element",,,"e of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of property graph gt | ("property graph label",,,"e of create_property_graph_tests.gt") | ("property graph label","{create_property_graph_tests,gt,e}",{}) + label v1 of property graph gt | ("property graph label",,,"v1 of create_property_graph_tests.gt") | ("property graph label","{create_property_graph_tests,gt,v1}",{}) + label v1 of vertex v1 of property graph gt | ("property graph element label",,,"v1 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v1}",{}) + label v1 of vertex v1 of property graph gt | ("property graph element label",,,"v1 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v1}",{}) + label v2 of property graph gt | ("property graph label",,,"v2 of create_property_graph_tests.gt") | ("property graph label","{create_property_graph_tests,gt,v2}",{}) + label v2 of vertex v2 of property graph gt | ("property graph element label",,,"v2 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v2}",{}) + label v2 of vertex v2 of property graph gt | ("property graph element label",,,"v2 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v2}",{}) + property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property a of property graph gt | ("property graph property",,,"a of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,a}",{}) + property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property b of property graph gt | ("property graph property",,,"b of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,b}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of property graph gt | ("property graph property",,,"c of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,c}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of property graph gt | ("property graph property",,,"k1 of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,k1}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of property graph gt | ("property graph property",,,"k2 of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,k2}",{}) + property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property m of property graph gt | ("property graph property",,,"m of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,m}",{}) + property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property n of property graph gt | ("property graph property",,,"n of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,n}",{}) + type gt | (type,create_property_graph_tests,gt,create_property_graph_tests.gt) | (type,{create_property_graph_tests.gt},{}) + type gt[] | (type,create_property_graph_tests,_gt,create_property_graph_tests.gt[]) | (type,{create_property_graph_tests.gt[]},{}) + vertex v1 of property graph gt | ("property graph element",,,"v1 of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,v1}",{}) + vertex v2 of property graph gt | ("property graph element",,,"v2 of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,v2}",{}) +(52 rows) + \a\t SELECT pg_get_propgraphdef('g2'::regclass); CREATE PROPERTY GRAPH create_property_graph_tests.g2 diff --git a/src/test/regress/expected/event_trigger.out b/src/test/regress/expected/event_trigger.out index 065f586310f..ed8d5df397e 100644 --- a/src/test/regress/expected/event_trigger.out +++ b/src/test/regress/expected/event_trigger.out @@ -173,6 +173,23 @@ NOTICE: test_event_trigger: ddl_command_end CREATE USER MAPPING alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; NOTICE: test_event_trigger: ddl_command_end ALTER DEFAULT PRIVILEGES +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE TABLE t2x (i int PRIMARY KEY, j text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); +NOTICE: test_event_trigger: ddl_command_end CREATE PROPERTY GRAPH +DROP PROPERTY GRAPH gx; +NOTICE: test_event_trigger: ddl_command_end DROP PROPERTY GRAPH +DROP TABLE t1x, t2x; +NOTICE: test_event_trigger: ddl_command_end DROP TABLE -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; ERROR: permission denied to change owner of event trigger "regress_event_trigger" diff --git a/src/test/regress/expected/object_address.out b/src/test/regress/expected/object_address.out index 97227d67a54..5e53f0b092e 100644 --- a/src/test/regress/expected/object_address.out +++ b/src/test/regress/expected/object_address.out @@ -67,7 +67,9 @@ DECLARE BEGIN FOR objtype IN VALUES ('toast table'), ('index column'), ('sequence column'), ('toast table column'), ('view column'), ('materialized view column'), - ('property graph element'), ('property graph label'), ('property graph property') + ('property graph element'), ('property graph element label'), + ('property graph label'), ('property graph label property'), + ('property graph property') LOOP BEGIN PERFORM pg_get_object_address(objtype, '{one}', '{}'); @@ -84,7 +86,9 @@ WARNING: error for toast table column: unsupported object type "toast table col WARNING: error for view column: unsupported object type "view column" WARNING: error for materialized view column: unsupported object type "materialized view column" WARNING: error for property graph element: unsupported object type "property graph element" +WARNING: error for property graph element label: unrecognized object type "property graph element label" WARNING: error for property graph label: unsupported object type "property graph label" +WARNING: error for property graph label property: unrecognized object type "property graph label property" WARNING: error for property graph property: unsupported object type "property graph property" -- miscellaneous other errors select * from pg_get_object_address('operator of access method', '{btree,integer_ops,1}', '{int4,bool}'); @@ -593,7 +597,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace @@ -653,6 +659,8 @@ ORDER BY objects.classid, objects.objid, objects.objsubid; ("(""parameter ACL"",,,)")|("(""parameter ACL"",,)")|NULL ("(""property graph element"",,,)")|("(""property graph element"",,)")|NULL ("(""property graph label"",,,)")|("(""property graph label"",,)")|NULL +("(""property graph element label"",,,)")|("(""property graph element label"",,)")|NULL ("(""property graph property"",,,)")|("(""property graph property"",,)")|NULL +("(""property graph label property"",,,)")|("(""property graph label property"",,)")|NULL -- restore normal output mode \a\t diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..9608dd5c4af 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -298,6 +298,29 @@ SELECT (pg_identify_object(classid, objid, objsubid)).* refobjid = 'create_property_graph_tests.g2'::regclass ORDER BY 1, 2, 3, 4; +-- test object address functions with recursive dependency walk +-- covers all property graph object types including indirect dependents +SELECT * +FROM ( + WITH RECURSIVE deps (classid, objid, objsubid, refclassid, refobjid, refobjsubid) AS ( + SELECT classid, objid, objsubid, + refclassid, refobjid, refobjsubid + FROM pg_depend + WHERE refclassid = 'pg_class'::regclass AND + refobjid = 'create_property_graph_tests.gt'::regclass + UNION ALL + SELECT d.classid, d.objid, d.objsubid, + d.refclassid, d.refobjid, d.refobjsubid + FROM pg_depend d + JOIN deps dp ON d.refclassid = dp.classid AND d.refobjid = dp.objid AND d.refobjsubid = dp.objsubid + ) + SELECT pg_describe_object(classid, objid, objsubid) as obj, + pg_identify_object(classid, objid, objsubid) as ident, + pg_identify_object_as_address(classid, objid, objsubid) as addr + FROM deps +) s +ORDER BY obj COLLATE "C", ident::text COLLATE "C"; + \a\t SELECT pg_get_propgraphdef('g2'::regclass); SELECT pg_get_propgraphdef('g3'::regclass); diff --git a/src/test/regress/sql/event_trigger.sql b/src/test/regress/sql/event_trigger.sql index 32e9bb58c5e..271f443378b 100644 --- a/src/test/regress/sql/event_trigger.sql +++ b/src/test/regress/sql/event_trigger.sql @@ -143,6 +143,19 @@ create user mapping for regress_evt_user server useless_server; alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +CREATE TABLE t2x (i int PRIMARY KEY, j text); + +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); + +DROP PROPERTY GRAPH gx; +DROP TABLE t1x, t2x; + -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; diff --git a/src/test/regress/sql/object_address.sql b/src/test/regress/sql/object_address.sql index 1bbe9457c1c..27109d421c7 100644 --- a/src/test/regress/sql/object_address.sql +++ b/src/test/regress/sql/object_address.sql @@ -67,7 +67,9 @@ DECLARE BEGIN FOR objtype IN VALUES ('toast table'), ('index column'), ('sequence column'), ('toast table column'), ('view column'), ('materialized view column'), - ('property graph element'), ('property graph label'), ('property graph property') + ('property graph element'), ('property graph element label'), + ('property graph label'), ('property graph label property'), + ('property graph property') LOOP BEGIN PERFORM pg_get_object_address(objtype, '{one}', '{}'); @@ -282,7 +284,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace -- 2.34.1 --R84XrR4Hgw0dH3Ec-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v3] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-23 09:27 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-23 09:27 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing them to hit the default case and error out with "unsupported object class". During DROP PROPERTY GRAPH, this manifests when an event trigger is active, because pg_event_trigger_ddl_commands() calls these functions. The same code paths are also reachable via pg_identify_object() and pg_identify_object_as_address(). This commit adds the missing cases. Test coverage is added in object_address.sql for these two catalog types and in create_property_graph.sql covering all property graph object types. A test in event_trigger.sql verifies that DROP PROPERTY GRAPH works correctly when an event trigger is active. Author: Bertrand Drouvot <[email protected]> Reviewed-by: Michael Paquier <[email protected]> Reviewed-by: Ashutosh Bapat <[email protected]> Discussion: https://postgr.es/m/aej1DkLwhyZWmtxJ@bdtpg --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 78 ++++++++++++++++ src/test/regress/expected/event_trigger.out | 17 ++++ src/test/regress/expected/object_address.out | 10 +- .../regress/sql/create_property_graph.sql | 23 +++++ src/test/regress/sql/event_trigger.sql | 13 +++ src/test/regress/sql/object_address.sql | 6 +- 7 files changed, 238 insertions(+), 2 deletions(-) 14.7% src/backend/catalog/ 75.5% src/test/regress/expected/ 9.7% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..eb9e17fb727 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -752,6 +752,84 @@ SELECT (pg_identify_object(classid, objid, objsubid)).* type | create_property_graph_tests | g2 | create_property_graph_tests.g2 (21 rows) +-- test object address functions with recursive dependency walk +-- covers all property graph object types including indirect dependents +SELECT * +FROM ( + WITH RECURSIVE deps (classid, objid, objsubid, refclassid, refobjid, refobjsubid) AS ( + SELECT classid, objid, objsubid, + refclassid, refobjid, refobjsubid + FROM pg_depend + WHERE refclassid = 'pg_class'::regclass AND + refobjid = 'create_property_graph_tests.gt'::regclass + UNION ALL + SELECT d.classid, d.objid, d.objsubid, + d.refclassid, d.refobjid, d.refobjsubid + FROM pg_depend d + JOIN deps dp ON d.refclassid = dp.classid AND d.refobjid = dp.objid AND d.refobjsubid = dp.objsubid + ) + SELECT pg_describe_object(classid, objid, objsubid) as obj, + pg_identify_object(classid, objid, objsubid) as ident, + pg_identify_object_as_address(classid, objid, objsubid) as addr + FROM deps +) s +ORDER BY obj COLLATE "C", ident::text COLLATE "C"; + obj | ident | addr +----------------------------------------------------------+----------------------------------------------------------------------------+---------------------------------------------------------------------------- + edge e of property graph gt | ("property graph element",,,"e of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,e}",{}) + edge e of property graph gt | ("property graph element",,,"e of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,e}",{}) + edge e of property graph gt | ("property graph element",,,"e of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of property graph gt | ("property graph label",,,"e of create_property_graph_tests.gt") | ("property graph label","{create_property_graph_tests,gt,e}",{}) + label v1 of property graph gt | ("property graph label",,,"v1 of create_property_graph_tests.gt") | ("property graph label","{create_property_graph_tests,gt,v1}",{}) + label v1 of vertex v1 of property graph gt | ("property graph element label",,,"v1 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v1}",{}) + label v1 of vertex v1 of property graph gt | ("property graph element label",,,"v1 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v1}",{}) + label v2 of property graph gt | ("property graph label",,,"v2 of create_property_graph_tests.gt") | ("property graph label","{create_property_graph_tests,gt,v2}",{}) + label v2 of vertex v2 of property graph gt | ("property graph element label",,,"v2 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v2}",{}) + label v2 of vertex v2 of property graph gt | ("property graph element label",,,"v2 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v2}",{}) + property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property a of property graph gt | ("property graph property",,,"a of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,a}",{}) + property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property b of property graph gt | ("property graph property",,,"b of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,b}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of property graph gt | ("property graph property",,,"c of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,c}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of property graph gt | ("property graph property",,,"k1 of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,k1}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of property graph gt | ("property graph property",,,"k2 of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,k2}",{}) + property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property m of property graph gt | ("property graph property",,,"m of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,m}",{}) + property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property n of property graph gt | ("property graph property",,,"n of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,n}",{}) + type gt | (type,create_property_graph_tests,gt,create_property_graph_tests.gt) | (type,{create_property_graph_tests.gt},{}) + type gt[] | (type,create_property_graph_tests,_gt,create_property_graph_tests.gt[]) | (type,{create_property_graph_tests.gt[]},{}) + vertex v1 of property graph gt | ("property graph element",,,"v1 of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,v1}",{}) + vertex v2 of property graph gt | ("property graph element",,,"v2 of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,v2}",{}) +(52 rows) + \a\t SELECT pg_get_propgraphdef('g2'::regclass); CREATE PROPERTY GRAPH create_property_graph_tests.g2 diff --git a/src/test/regress/expected/event_trigger.out b/src/test/regress/expected/event_trigger.out index 065f586310f..ed8d5df397e 100644 --- a/src/test/regress/expected/event_trigger.out +++ b/src/test/regress/expected/event_trigger.out @@ -173,6 +173,23 @@ NOTICE: test_event_trigger: ddl_command_end CREATE USER MAPPING alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; NOTICE: test_event_trigger: ddl_command_end ALTER DEFAULT PRIVILEGES +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE TABLE t2x (i int PRIMARY KEY, j text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); +NOTICE: test_event_trigger: ddl_command_end CREATE PROPERTY GRAPH +DROP PROPERTY GRAPH gx; +NOTICE: test_event_trigger: ddl_command_end DROP PROPERTY GRAPH +DROP TABLE t1x, t2x; +NOTICE: test_event_trigger: ddl_command_end DROP TABLE -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; ERROR: permission denied to change owner of event trigger "regress_event_trigger" diff --git a/src/test/regress/expected/object_address.out b/src/test/regress/expected/object_address.out index 97227d67a54..5e53f0b092e 100644 --- a/src/test/regress/expected/object_address.out +++ b/src/test/regress/expected/object_address.out @@ -67,7 +67,9 @@ DECLARE BEGIN FOR objtype IN VALUES ('toast table'), ('index column'), ('sequence column'), ('toast table column'), ('view column'), ('materialized view column'), - ('property graph element'), ('property graph label'), ('property graph property') + ('property graph element'), ('property graph element label'), + ('property graph label'), ('property graph label property'), + ('property graph property') LOOP BEGIN PERFORM pg_get_object_address(objtype, '{one}', '{}'); @@ -84,7 +86,9 @@ WARNING: error for toast table column: unsupported object type "toast table col WARNING: error for view column: unsupported object type "view column" WARNING: error for materialized view column: unsupported object type "materialized view column" WARNING: error for property graph element: unsupported object type "property graph element" +WARNING: error for property graph element label: unrecognized object type "property graph element label" WARNING: error for property graph label: unsupported object type "property graph label" +WARNING: error for property graph label property: unrecognized object type "property graph label property" WARNING: error for property graph property: unsupported object type "property graph property" -- miscellaneous other errors select * from pg_get_object_address('operator of access method', '{btree,integer_ops,1}', '{int4,bool}'); @@ -593,7 +597,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace @@ -653,6 +659,8 @@ ORDER BY objects.classid, objects.objid, objects.objsubid; ("(""parameter ACL"",,,)")|("(""parameter ACL"",,)")|NULL ("(""property graph element"",,,)")|("(""property graph element"",,)")|NULL ("(""property graph label"",,,)")|("(""property graph label"",,)")|NULL +("(""property graph element label"",,,)")|("(""property graph element label"",,)")|NULL ("(""property graph property"",,,)")|("(""property graph property"",,)")|NULL +("(""property graph label property"",,,)")|("(""property graph label property"",,)")|NULL -- restore normal output mode \a\t diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..9608dd5c4af 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -298,6 +298,29 @@ SELECT (pg_identify_object(classid, objid, objsubid)).* refobjid = 'create_property_graph_tests.g2'::regclass ORDER BY 1, 2, 3, 4; +-- test object address functions with recursive dependency walk +-- covers all property graph object types including indirect dependents +SELECT * +FROM ( + WITH RECURSIVE deps (classid, objid, objsubid, refclassid, refobjid, refobjsubid) AS ( + SELECT classid, objid, objsubid, + refclassid, refobjid, refobjsubid + FROM pg_depend + WHERE refclassid = 'pg_class'::regclass AND + refobjid = 'create_property_graph_tests.gt'::regclass + UNION ALL + SELECT d.classid, d.objid, d.objsubid, + d.refclassid, d.refobjid, d.refobjsubid + FROM pg_depend d + JOIN deps dp ON d.refclassid = dp.classid AND d.refobjid = dp.objid AND d.refobjsubid = dp.objsubid + ) + SELECT pg_describe_object(classid, objid, objsubid) as obj, + pg_identify_object(classid, objid, objsubid) as ident, + pg_identify_object_as_address(classid, objid, objsubid) as addr + FROM deps +) s +ORDER BY obj COLLATE "C", ident::text COLLATE "C"; + \a\t SELECT pg_get_propgraphdef('g2'::regclass); SELECT pg_get_propgraphdef('g3'::regclass); diff --git a/src/test/regress/sql/event_trigger.sql b/src/test/regress/sql/event_trigger.sql index 32e9bb58c5e..271f443378b 100644 --- a/src/test/regress/sql/event_trigger.sql +++ b/src/test/regress/sql/event_trigger.sql @@ -143,6 +143,19 @@ create user mapping for regress_evt_user server useless_server; alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +CREATE TABLE t2x (i int PRIMARY KEY, j text); + +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); + +DROP PROPERTY GRAPH gx; +DROP TABLE t1x, t2x; + -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; diff --git a/src/test/regress/sql/object_address.sql b/src/test/regress/sql/object_address.sql index 1bbe9457c1c..27109d421c7 100644 --- a/src/test/regress/sql/object_address.sql +++ b/src/test/regress/sql/object_address.sql @@ -67,7 +67,9 @@ DECLARE BEGIN FOR objtype IN VALUES ('toast table'), ('index column'), ('sequence column'), ('toast table column'), ('view column'), ('materialized view column'), - ('property graph element'), ('property graph label'), ('property graph property') + ('property graph element'), ('property graph element label'), + ('property graph label'), ('property graph label property'), + ('property graph property') LOOP BEGIN PERFORM pg_get_object_address(objtype, '{one}', '{}'); @@ -282,7 +284,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace -- 2.34.1 --R84XrR4Hgw0dH3Ec-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v2] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-23 09:27 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-23 09:27 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing them to hit the default case and error out with "unsupported object class". During DROP PROPERTY GRAPH, this manifests when an event trigger is active, because pg_event_trigger_ddl_commands() calls these functions. The same code paths are also reachable via pg_identify_object() and pg_identify_object_as_address(). This commit adds the missing cases. Test coverage is added in object_address.sql for these two catalog types via the zero-OID test that exercises pg_identify_object() and pg_identify_object_as_address(). A test in event_trigger.sql verifies that DROP PROPERTY GRAPH works correctly when an event trigger is active. Author: Bertrand Drouvot <[email protected]> Reviewed-by: Michael Paquier <[email protected]> Reviewed-by: Ashutosh Bapat <[email protected]> Discussion: https://postgr.es/m/aej1DkLwhyZWmtxJ@bdtpg --- src/backend/catalog/objectaddress.c | 93 ++++++++++++++++++++ src/test/regress/expected/event_trigger.out | 17 ++++ src/test/regress/expected/object_address.out | 4 + src/test/regress/sql/event_trigger.sql | 13 +++ src/test/regress/sql/object_address.sql | 2 + 5 files changed, 129 insertions(+) 62.4% src/backend/catalog/ 25.6% src/test/regress/expected/ 11.8% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/event_trigger.out b/src/test/regress/expected/event_trigger.out index 065f586310f..ed8d5df397e 100644 --- a/src/test/regress/expected/event_trigger.out +++ b/src/test/regress/expected/event_trigger.out @@ -173,6 +173,23 @@ NOTICE: test_event_trigger: ddl_command_end CREATE USER MAPPING alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; NOTICE: test_event_trigger: ddl_command_end ALTER DEFAULT PRIVILEGES +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE TABLE t2x (i int PRIMARY KEY, j text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); +NOTICE: test_event_trigger: ddl_command_end CREATE PROPERTY GRAPH +DROP PROPERTY GRAPH gx; +NOTICE: test_event_trigger: ddl_command_end DROP PROPERTY GRAPH +DROP TABLE t1x, t2x; +NOTICE: test_event_trigger: ddl_command_end DROP TABLE -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; ERROR: permission denied to change owner of event trigger "regress_event_trigger" diff --git a/src/test/regress/expected/object_address.out b/src/test/regress/expected/object_address.out index 97227d67a54..729c3537f25 100644 --- a/src/test/regress/expected/object_address.out +++ b/src/test/regress/expected/object_address.out @@ -593,7 +593,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace @@ -653,6 +655,8 @@ ORDER BY objects.classid, objects.objid, objects.objsubid; ("(""parameter ACL"",,,)")|("(""parameter ACL"",,)")|NULL ("(""property graph element"",,,)")|("(""property graph element"",,)")|NULL ("(""property graph label"",,,)")|("(""property graph label"",,)")|NULL +("(""property graph element label"",,,)")|("(""property graph element label"",,)")|NULL ("(""property graph property"",,,)")|("(""property graph property"",,)")|NULL +("(""property graph label property"",,,)")|("(""property graph label property"",,)")|NULL -- restore normal output mode \a\t diff --git a/src/test/regress/sql/event_trigger.sql b/src/test/regress/sql/event_trigger.sql index 32e9bb58c5e..271f443378b 100644 --- a/src/test/regress/sql/event_trigger.sql +++ b/src/test/regress/sql/event_trigger.sql @@ -143,6 +143,19 @@ create user mapping for regress_evt_user server useless_server; alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +CREATE TABLE t2x (i int PRIMARY KEY, j text); + +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); + +DROP PROPERTY GRAPH gx; +DROP TABLE t1x, t2x; + -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; diff --git a/src/test/regress/sql/object_address.sql b/src/test/regress/sql/object_address.sql index 1bbe9457c1c..620dacf1045 100644 --- a/src/test/regress/sql/object_address.sql +++ b/src/test/regress/sql/object_address.sql @@ -282,7 +282,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace -- 2.34.1 --gtUR827Uq8d5gVsQ-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v3] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-23 09:27 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-23 09:27 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing them to hit the default case and error out with "unsupported object class". During DROP PROPERTY GRAPH, this manifests when an event trigger is active, because pg_event_trigger_ddl_commands() calls these functions. The same code paths are also reachable via pg_identify_object() and pg_identify_object_as_address(). This commit adds the missing cases. Test coverage is added in object_address.sql for these two catalog types and in create_property_graph.sql covering all property graph object types. A test in event_trigger.sql verifies that DROP PROPERTY GRAPH works correctly when an event trigger is active. Author: Bertrand Drouvot <[email protected]> Reviewed-by: Michael Paquier <[email protected]> Reviewed-by: Ashutosh Bapat <[email protected]> Discussion: https://postgr.es/m/aej1DkLwhyZWmtxJ@bdtpg --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 78 ++++++++++++++++ src/test/regress/expected/event_trigger.out | 17 ++++ src/test/regress/expected/object_address.out | 10 +- .../regress/sql/create_property_graph.sql | 23 +++++ src/test/regress/sql/event_trigger.sql | 13 +++ src/test/regress/sql/object_address.sql | 6 +- 7 files changed, 238 insertions(+), 2 deletions(-) 14.7% src/backend/catalog/ 75.5% src/test/regress/expected/ 9.7% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..eb9e17fb727 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -752,6 +752,84 @@ SELECT (pg_identify_object(classid, objid, objsubid)).* type | create_property_graph_tests | g2 | create_property_graph_tests.g2 (21 rows) +-- test object address functions with recursive dependency walk +-- covers all property graph object types including indirect dependents +SELECT * +FROM ( + WITH RECURSIVE deps (classid, objid, objsubid, refclassid, refobjid, refobjsubid) AS ( + SELECT classid, objid, objsubid, + refclassid, refobjid, refobjsubid + FROM pg_depend + WHERE refclassid = 'pg_class'::regclass AND + refobjid = 'create_property_graph_tests.gt'::regclass + UNION ALL + SELECT d.classid, d.objid, d.objsubid, + d.refclassid, d.refobjid, d.refobjsubid + FROM pg_depend d + JOIN deps dp ON d.refclassid = dp.classid AND d.refobjid = dp.objid AND d.refobjsubid = dp.objsubid + ) + SELECT pg_describe_object(classid, objid, objsubid) as obj, + pg_identify_object(classid, objid, objsubid) as ident, + pg_identify_object_as_address(classid, objid, objsubid) as addr + FROM deps +) s +ORDER BY obj COLLATE "C", ident::text COLLATE "C"; + obj | ident | addr +----------------------------------------------------------+----------------------------------------------------------------------------+---------------------------------------------------------------------------- + edge e of property graph gt | ("property graph element",,,"e of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,e}",{}) + edge e of property graph gt | ("property graph element",,,"e of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,e}",{}) + edge e of property graph gt | ("property graph element",,,"e of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of property graph gt | ("property graph label",,,"e of create_property_graph_tests.gt") | ("property graph label","{create_property_graph_tests,gt,e}",{}) + label v1 of property graph gt | ("property graph label",,,"v1 of create_property_graph_tests.gt") | ("property graph label","{create_property_graph_tests,gt,v1}",{}) + label v1 of vertex v1 of property graph gt | ("property graph element label",,,"v1 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v1}",{}) + label v1 of vertex v1 of property graph gt | ("property graph element label",,,"v1 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v1}",{}) + label v2 of property graph gt | ("property graph label",,,"v2 of create_property_graph_tests.gt") | ("property graph label","{create_property_graph_tests,gt,v2}",{}) + label v2 of vertex v2 of property graph gt | ("property graph element label",,,"v2 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v2}",{}) + label v2 of vertex v2 of property graph gt | ("property graph element label",,,"v2 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v2}",{}) + property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property a of property graph gt | ("property graph property",,,"a of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,a}",{}) + property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property b of property graph gt | ("property graph property",,,"b of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,b}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of property graph gt | ("property graph property",,,"c of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,c}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of property graph gt | ("property graph property",,,"k1 of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,k1}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of property graph gt | ("property graph property",,,"k2 of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,k2}",{}) + property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property m of property graph gt | ("property graph property",,,"m of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,m}",{}) + property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property n of property graph gt | ("property graph property",,,"n of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,n}",{}) + type gt | (type,create_property_graph_tests,gt,create_property_graph_tests.gt) | (type,{create_property_graph_tests.gt},{}) + type gt[] | (type,create_property_graph_tests,_gt,create_property_graph_tests.gt[]) | (type,{create_property_graph_tests.gt[]},{}) + vertex v1 of property graph gt | ("property graph element",,,"v1 of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,v1}",{}) + vertex v2 of property graph gt | ("property graph element",,,"v2 of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,v2}",{}) +(52 rows) + \a\t SELECT pg_get_propgraphdef('g2'::regclass); CREATE PROPERTY GRAPH create_property_graph_tests.g2 diff --git a/src/test/regress/expected/event_trigger.out b/src/test/regress/expected/event_trigger.out index 065f586310f..ed8d5df397e 100644 --- a/src/test/regress/expected/event_trigger.out +++ b/src/test/regress/expected/event_trigger.out @@ -173,6 +173,23 @@ NOTICE: test_event_trigger: ddl_command_end CREATE USER MAPPING alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; NOTICE: test_event_trigger: ddl_command_end ALTER DEFAULT PRIVILEGES +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE TABLE t2x (i int PRIMARY KEY, j text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); +NOTICE: test_event_trigger: ddl_command_end CREATE PROPERTY GRAPH +DROP PROPERTY GRAPH gx; +NOTICE: test_event_trigger: ddl_command_end DROP PROPERTY GRAPH +DROP TABLE t1x, t2x; +NOTICE: test_event_trigger: ddl_command_end DROP TABLE -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; ERROR: permission denied to change owner of event trigger "regress_event_trigger" diff --git a/src/test/regress/expected/object_address.out b/src/test/regress/expected/object_address.out index 97227d67a54..5e53f0b092e 100644 --- a/src/test/regress/expected/object_address.out +++ b/src/test/regress/expected/object_address.out @@ -67,7 +67,9 @@ DECLARE BEGIN FOR objtype IN VALUES ('toast table'), ('index column'), ('sequence column'), ('toast table column'), ('view column'), ('materialized view column'), - ('property graph element'), ('property graph label'), ('property graph property') + ('property graph element'), ('property graph element label'), + ('property graph label'), ('property graph label property'), + ('property graph property') LOOP BEGIN PERFORM pg_get_object_address(objtype, '{one}', '{}'); @@ -84,7 +86,9 @@ WARNING: error for toast table column: unsupported object type "toast table col WARNING: error for view column: unsupported object type "view column" WARNING: error for materialized view column: unsupported object type "materialized view column" WARNING: error for property graph element: unsupported object type "property graph element" +WARNING: error for property graph element label: unrecognized object type "property graph element label" WARNING: error for property graph label: unsupported object type "property graph label" +WARNING: error for property graph label property: unrecognized object type "property graph label property" WARNING: error for property graph property: unsupported object type "property graph property" -- miscellaneous other errors select * from pg_get_object_address('operator of access method', '{btree,integer_ops,1}', '{int4,bool}'); @@ -593,7 +597,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace @@ -653,6 +659,8 @@ ORDER BY objects.classid, objects.objid, objects.objsubid; ("(""parameter ACL"",,,)")|("(""parameter ACL"",,)")|NULL ("(""property graph element"",,,)")|("(""property graph element"",,)")|NULL ("(""property graph label"",,,)")|("(""property graph label"",,)")|NULL +("(""property graph element label"",,,)")|("(""property graph element label"",,)")|NULL ("(""property graph property"",,,)")|("(""property graph property"",,)")|NULL +("(""property graph label property"",,,)")|("(""property graph label property"",,)")|NULL -- restore normal output mode \a\t diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..9608dd5c4af 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -298,6 +298,29 @@ SELECT (pg_identify_object(classid, objid, objsubid)).* refobjid = 'create_property_graph_tests.g2'::regclass ORDER BY 1, 2, 3, 4; +-- test object address functions with recursive dependency walk +-- covers all property graph object types including indirect dependents +SELECT * +FROM ( + WITH RECURSIVE deps (classid, objid, objsubid, refclassid, refobjid, refobjsubid) AS ( + SELECT classid, objid, objsubid, + refclassid, refobjid, refobjsubid + FROM pg_depend + WHERE refclassid = 'pg_class'::regclass AND + refobjid = 'create_property_graph_tests.gt'::regclass + UNION ALL + SELECT d.classid, d.objid, d.objsubid, + d.refclassid, d.refobjid, d.refobjsubid + FROM pg_depend d + JOIN deps dp ON d.refclassid = dp.classid AND d.refobjid = dp.objid AND d.refobjsubid = dp.objsubid + ) + SELECT pg_describe_object(classid, objid, objsubid) as obj, + pg_identify_object(classid, objid, objsubid) as ident, + pg_identify_object_as_address(classid, objid, objsubid) as addr + FROM deps +) s +ORDER BY obj COLLATE "C", ident::text COLLATE "C"; + \a\t SELECT pg_get_propgraphdef('g2'::regclass); SELECT pg_get_propgraphdef('g3'::regclass); diff --git a/src/test/regress/sql/event_trigger.sql b/src/test/regress/sql/event_trigger.sql index 32e9bb58c5e..271f443378b 100644 --- a/src/test/regress/sql/event_trigger.sql +++ b/src/test/regress/sql/event_trigger.sql @@ -143,6 +143,19 @@ create user mapping for regress_evt_user server useless_server; alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +CREATE TABLE t2x (i int PRIMARY KEY, j text); + +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); + +DROP PROPERTY GRAPH gx; +DROP TABLE t1x, t2x; + -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; diff --git a/src/test/regress/sql/object_address.sql b/src/test/regress/sql/object_address.sql index 1bbe9457c1c..27109d421c7 100644 --- a/src/test/regress/sql/object_address.sql +++ b/src/test/regress/sql/object_address.sql @@ -67,7 +67,9 @@ DECLARE BEGIN FOR objtype IN VALUES ('toast table'), ('index column'), ('sequence column'), ('toast table column'), ('view column'), ('materialized view column'), - ('property graph element'), ('property graph label'), ('property graph property') + ('property graph element'), ('property graph element label'), + ('property graph label'), ('property graph label property'), + ('property graph property') LOOP BEGIN PERFORM pg_get_object_address(objtype, '{one}', '{}'); @@ -282,7 +284,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace -- 2.34.1 --R84XrR4Hgw0dH3Ec-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v3] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-23 09:27 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-23 09:27 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing them to hit the default case and error out with "unsupported object class". During DROP PROPERTY GRAPH, this manifests when an event trigger is active, because pg_event_trigger_ddl_commands() calls these functions. The same code paths are also reachable via pg_identify_object() and pg_identify_object_as_address(). This commit adds the missing cases. Test coverage is added in object_address.sql for these two catalog types and in create_property_graph.sql covering all property graph object types. A test in event_trigger.sql verifies that DROP PROPERTY GRAPH works correctly when an event trigger is active. Author: Bertrand Drouvot <[email protected]> Reviewed-by: Michael Paquier <[email protected]> Reviewed-by: Ashutosh Bapat <[email protected]> Discussion: https://postgr.es/m/aej1DkLwhyZWmtxJ@bdtpg --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 78 ++++++++++++++++ src/test/regress/expected/event_trigger.out | 17 ++++ src/test/regress/expected/object_address.out | 10 +- .../regress/sql/create_property_graph.sql | 23 +++++ src/test/regress/sql/event_trigger.sql | 13 +++ src/test/regress/sql/object_address.sql | 6 +- 7 files changed, 238 insertions(+), 2 deletions(-) 14.7% src/backend/catalog/ 75.5% src/test/regress/expected/ 9.7% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..eb9e17fb727 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -752,6 +752,84 @@ SELECT (pg_identify_object(classid, objid, objsubid)).* type | create_property_graph_tests | g2 | create_property_graph_tests.g2 (21 rows) +-- test object address functions with recursive dependency walk +-- covers all property graph object types including indirect dependents +SELECT * +FROM ( + WITH RECURSIVE deps (classid, objid, objsubid, refclassid, refobjid, refobjsubid) AS ( + SELECT classid, objid, objsubid, + refclassid, refobjid, refobjsubid + FROM pg_depend + WHERE refclassid = 'pg_class'::regclass AND + refobjid = 'create_property_graph_tests.gt'::regclass + UNION ALL + SELECT d.classid, d.objid, d.objsubid, + d.refclassid, d.refobjid, d.refobjsubid + FROM pg_depend d + JOIN deps dp ON d.refclassid = dp.classid AND d.refobjid = dp.objid AND d.refobjsubid = dp.objsubid + ) + SELECT pg_describe_object(classid, objid, objsubid) as obj, + pg_identify_object(classid, objid, objsubid) as ident, + pg_identify_object_as_address(classid, objid, objsubid) as addr + FROM deps +) s +ORDER BY obj COLLATE "C", ident::text COLLATE "C"; + obj | ident | addr +----------------------------------------------------------+----------------------------------------------------------------------------+---------------------------------------------------------------------------- + edge e of property graph gt | ("property graph element",,,"e of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,e}",{}) + edge e of property graph gt | ("property graph element",,,"e of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,e}",{}) + edge e of property graph gt | ("property graph element",,,"e of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of property graph gt | ("property graph label",,,"e of create_property_graph_tests.gt") | ("property graph label","{create_property_graph_tests,gt,e}",{}) + label v1 of property graph gt | ("property graph label",,,"v1 of create_property_graph_tests.gt") | ("property graph label","{create_property_graph_tests,gt,v1}",{}) + label v1 of vertex v1 of property graph gt | ("property graph element label",,,"v1 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v1}",{}) + label v1 of vertex v1 of property graph gt | ("property graph element label",,,"v1 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v1}",{}) + label v2 of property graph gt | ("property graph label",,,"v2 of create_property_graph_tests.gt") | ("property graph label","{create_property_graph_tests,gt,v2}",{}) + label v2 of vertex v2 of property graph gt | ("property graph element label",,,"v2 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v2}",{}) + label v2 of vertex v2 of property graph gt | ("property graph element label",,,"v2 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v2}",{}) + property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property a of property graph gt | ("property graph property",,,"a of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,a}",{}) + property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property b of property graph gt | ("property graph property",,,"b of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,b}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of property graph gt | ("property graph property",,,"c of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,c}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of property graph gt | ("property graph property",,,"k1 of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,k1}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of property graph gt | ("property graph property",,,"k2 of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,k2}",{}) + property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property m of property graph gt | ("property graph property",,,"m of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,m}",{}) + property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property n of property graph gt | ("property graph property",,,"n of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,n}",{}) + type gt | (type,create_property_graph_tests,gt,create_property_graph_tests.gt) | (type,{create_property_graph_tests.gt},{}) + type gt[] | (type,create_property_graph_tests,_gt,create_property_graph_tests.gt[]) | (type,{create_property_graph_tests.gt[]},{}) + vertex v1 of property graph gt | ("property graph element",,,"v1 of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,v1}",{}) + vertex v2 of property graph gt | ("property graph element",,,"v2 of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,v2}",{}) +(52 rows) + \a\t SELECT pg_get_propgraphdef('g2'::regclass); CREATE PROPERTY GRAPH create_property_graph_tests.g2 diff --git a/src/test/regress/expected/event_trigger.out b/src/test/regress/expected/event_trigger.out index 065f586310f..ed8d5df397e 100644 --- a/src/test/regress/expected/event_trigger.out +++ b/src/test/regress/expected/event_trigger.out @@ -173,6 +173,23 @@ NOTICE: test_event_trigger: ddl_command_end CREATE USER MAPPING alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; NOTICE: test_event_trigger: ddl_command_end ALTER DEFAULT PRIVILEGES +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE TABLE t2x (i int PRIMARY KEY, j text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); +NOTICE: test_event_trigger: ddl_command_end CREATE PROPERTY GRAPH +DROP PROPERTY GRAPH gx; +NOTICE: test_event_trigger: ddl_command_end DROP PROPERTY GRAPH +DROP TABLE t1x, t2x; +NOTICE: test_event_trigger: ddl_command_end DROP TABLE -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; ERROR: permission denied to change owner of event trigger "regress_event_trigger" diff --git a/src/test/regress/expected/object_address.out b/src/test/regress/expected/object_address.out index 97227d67a54..5e53f0b092e 100644 --- a/src/test/regress/expected/object_address.out +++ b/src/test/regress/expected/object_address.out @@ -67,7 +67,9 @@ DECLARE BEGIN FOR objtype IN VALUES ('toast table'), ('index column'), ('sequence column'), ('toast table column'), ('view column'), ('materialized view column'), - ('property graph element'), ('property graph label'), ('property graph property') + ('property graph element'), ('property graph element label'), + ('property graph label'), ('property graph label property'), + ('property graph property') LOOP BEGIN PERFORM pg_get_object_address(objtype, '{one}', '{}'); @@ -84,7 +86,9 @@ WARNING: error for toast table column: unsupported object type "toast table col WARNING: error for view column: unsupported object type "view column" WARNING: error for materialized view column: unsupported object type "materialized view column" WARNING: error for property graph element: unsupported object type "property graph element" +WARNING: error for property graph element label: unrecognized object type "property graph element label" WARNING: error for property graph label: unsupported object type "property graph label" +WARNING: error for property graph label property: unrecognized object type "property graph label property" WARNING: error for property graph property: unsupported object type "property graph property" -- miscellaneous other errors select * from pg_get_object_address('operator of access method', '{btree,integer_ops,1}', '{int4,bool}'); @@ -593,7 +597,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace @@ -653,6 +659,8 @@ ORDER BY objects.classid, objects.objid, objects.objsubid; ("(""parameter ACL"",,,)")|("(""parameter ACL"",,)")|NULL ("(""property graph element"",,,)")|("(""property graph element"",,)")|NULL ("(""property graph label"",,,)")|("(""property graph label"",,)")|NULL +("(""property graph element label"",,,)")|("(""property graph element label"",,)")|NULL ("(""property graph property"",,,)")|("(""property graph property"",,)")|NULL +("(""property graph label property"",,,)")|("(""property graph label property"",,)")|NULL -- restore normal output mode \a\t diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..9608dd5c4af 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -298,6 +298,29 @@ SELECT (pg_identify_object(classid, objid, objsubid)).* refobjid = 'create_property_graph_tests.g2'::regclass ORDER BY 1, 2, 3, 4; +-- test object address functions with recursive dependency walk +-- covers all property graph object types including indirect dependents +SELECT * +FROM ( + WITH RECURSIVE deps (classid, objid, objsubid, refclassid, refobjid, refobjsubid) AS ( + SELECT classid, objid, objsubid, + refclassid, refobjid, refobjsubid + FROM pg_depend + WHERE refclassid = 'pg_class'::regclass AND + refobjid = 'create_property_graph_tests.gt'::regclass + UNION ALL + SELECT d.classid, d.objid, d.objsubid, + d.refclassid, d.refobjid, d.refobjsubid + FROM pg_depend d + JOIN deps dp ON d.refclassid = dp.classid AND d.refobjid = dp.objid AND d.refobjsubid = dp.objsubid + ) + SELECT pg_describe_object(classid, objid, objsubid) as obj, + pg_identify_object(classid, objid, objsubid) as ident, + pg_identify_object_as_address(classid, objid, objsubid) as addr + FROM deps +) s +ORDER BY obj COLLATE "C", ident::text COLLATE "C"; + \a\t SELECT pg_get_propgraphdef('g2'::regclass); SELECT pg_get_propgraphdef('g3'::regclass); diff --git a/src/test/regress/sql/event_trigger.sql b/src/test/regress/sql/event_trigger.sql index 32e9bb58c5e..271f443378b 100644 --- a/src/test/regress/sql/event_trigger.sql +++ b/src/test/regress/sql/event_trigger.sql @@ -143,6 +143,19 @@ create user mapping for regress_evt_user server useless_server; alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +CREATE TABLE t2x (i int PRIMARY KEY, j text); + +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); + +DROP PROPERTY GRAPH gx; +DROP TABLE t1x, t2x; + -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; diff --git a/src/test/regress/sql/object_address.sql b/src/test/regress/sql/object_address.sql index 1bbe9457c1c..27109d421c7 100644 --- a/src/test/regress/sql/object_address.sql +++ b/src/test/regress/sql/object_address.sql @@ -67,7 +67,9 @@ DECLARE BEGIN FOR objtype IN VALUES ('toast table'), ('index column'), ('sequence column'), ('toast table column'), ('view column'), ('materialized view column'), - ('property graph element'), ('property graph label'), ('property graph property') + ('property graph element'), ('property graph element label'), + ('property graph label'), ('property graph label property'), + ('property graph property') LOOP BEGIN PERFORM pg_get_object_address(objtype, '{one}', '{}'); @@ -282,7 +284,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace -- 2.34.1 --R84XrR4Hgw0dH3Ec-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v2] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-23 09:27 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-23 09:27 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing them to hit the default case and error out with "unsupported object class". During DROP PROPERTY GRAPH, this manifests when an event trigger is active, because pg_event_trigger_ddl_commands() calls these functions. The same code paths are also reachable via pg_identify_object() and pg_identify_object_as_address(). This commit adds the missing cases. Test coverage is added in object_address.sql for these two catalog types via the zero-OID test that exercises pg_identify_object() and pg_identify_object_as_address(). A test in event_trigger.sql verifies that DROP PROPERTY GRAPH works correctly when an event trigger is active. Author: Bertrand Drouvot <[email protected]> Reviewed-by: Michael Paquier <[email protected]> Reviewed-by: Ashutosh Bapat <[email protected]> Discussion: https://postgr.es/m/aej1DkLwhyZWmtxJ@bdtpg --- src/backend/catalog/objectaddress.c | 93 ++++++++++++++++++++ src/test/regress/expected/event_trigger.out | 17 ++++ src/test/regress/expected/object_address.out | 4 + src/test/regress/sql/event_trigger.sql | 13 +++ src/test/regress/sql/object_address.sql | 2 + 5 files changed, 129 insertions(+) 62.4% src/backend/catalog/ 25.6% src/test/regress/expected/ 11.8% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/event_trigger.out b/src/test/regress/expected/event_trigger.out index 065f586310f..ed8d5df397e 100644 --- a/src/test/regress/expected/event_trigger.out +++ b/src/test/regress/expected/event_trigger.out @@ -173,6 +173,23 @@ NOTICE: test_event_trigger: ddl_command_end CREATE USER MAPPING alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; NOTICE: test_event_trigger: ddl_command_end ALTER DEFAULT PRIVILEGES +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE TABLE t2x (i int PRIMARY KEY, j text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); +NOTICE: test_event_trigger: ddl_command_end CREATE PROPERTY GRAPH +DROP PROPERTY GRAPH gx; +NOTICE: test_event_trigger: ddl_command_end DROP PROPERTY GRAPH +DROP TABLE t1x, t2x; +NOTICE: test_event_trigger: ddl_command_end DROP TABLE -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; ERROR: permission denied to change owner of event trigger "regress_event_trigger" diff --git a/src/test/regress/expected/object_address.out b/src/test/regress/expected/object_address.out index 97227d67a54..729c3537f25 100644 --- a/src/test/regress/expected/object_address.out +++ b/src/test/regress/expected/object_address.out @@ -593,7 +593,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace @@ -653,6 +655,8 @@ ORDER BY objects.classid, objects.objid, objects.objsubid; ("(""parameter ACL"",,,)")|("(""parameter ACL"",,)")|NULL ("(""property graph element"",,,)")|("(""property graph element"",,)")|NULL ("(""property graph label"",,,)")|("(""property graph label"",,)")|NULL +("(""property graph element label"",,,)")|("(""property graph element label"",,)")|NULL ("(""property graph property"",,,)")|("(""property graph property"",,)")|NULL +("(""property graph label property"",,,)")|("(""property graph label property"",,)")|NULL -- restore normal output mode \a\t diff --git a/src/test/regress/sql/event_trigger.sql b/src/test/regress/sql/event_trigger.sql index 32e9bb58c5e..271f443378b 100644 --- a/src/test/regress/sql/event_trigger.sql +++ b/src/test/regress/sql/event_trigger.sql @@ -143,6 +143,19 @@ create user mapping for regress_evt_user server useless_server; alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +CREATE TABLE t2x (i int PRIMARY KEY, j text); + +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); + +DROP PROPERTY GRAPH gx; +DROP TABLE t1x, t2x; + -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; diff --git a/src/test/regress/sql/object_address.sql b/src/test/regress/sql/object_address.sql index 1bbe9457c1c..620dacf1045 100644 --- a/src/test/regress/sql/object_address.sql +++ b/src/test/regress/sql/object_address.sql @@ -282,7 +282,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace -- 2.34.1 --gtUR827Uq8d5gVsQ-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v3] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-23 09:27 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-23 09:27 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing them to hit the default case and error out with "unsupported object class". During DROP PROPERTY GRAPH, this manifests when an event trigger is active, because pg_event_trigger_ddl_commands() calls these functions. The same code paths are also reachable via pg_identify_object() and pg_identify_object_as_address(). This commit adds the missing cases. Test coverage is added in object_address.sql for these two catalog types and in create_property_graph.sql covering all property graph object types. A test in event_trigger.sql verifies that DROP PROPERTY GRAPH works correctly when an event trigger is active. Author: Bertrand Drouvot <[email protected]> Reviewed-by: Michael Paquier <[email protected]> Reviewed-by: Ashutosh Bapat <[email protected]> Discussion: https://postgr.es/m/aej1DkLwhyZWmtxJ@bdtpg --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 78 ++++++++++++++++ src/test/regress/expected/event_trigger.out | 17 ++++ src/test/regress/expected/object_address.out | 10 +- .../regress/sql/create_property_graph.sql | 23 +++++ src/test/regress/sql/event_trigger.sql | 13 +++ src/test/regress/sql/object_address.sql | 6 +- 7 files changed, 238 insertions(+), 2 deletions(-) 14.7% src/backend/catalog/ 75.5% src/test/regress/expected/ 9.7% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..eb9e17fb727 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -752,6 +752,84 @@ SELECT (pg_identify_object(classid, objid, objsubid)).* type | create_property_graph_tests | g2 | create_property_graph_tests.g2 (21 rows) +-- test object address functions with recursive dependency walk +-- covers all property graph object types including indirect dependents +SELECT * +FROM ( + WITH RECURSIVE deps (classid, objid, objsubid, refclassid, refobjid, refobjsubid) AS ( + SELECT classid, objid, objsubid, + refclassid, refobjid, refobjsubid + FROM pg_depend + WHERE refclassid = 'pg_class'::regclass AND + refobjid = 'create_property_graph_tests.gt'::regclass + UNION ALL + SELECT d.classid, d.objid, d.objsubid, + d.refclassid, d.refobjid, d.refobjsubid + FROM pg_depend d + JOIN deps dp ON d.refclassid = dp.classid AND d.refobjid = dp.objid AND d.refobjsubid = dp.objsubid + ) + SELECT pg_describe_object(classid, objid, objsubid) as obj, + pg_identify_object(classid, objid, objsubid) as ident, + pg_identify_object_as_address(classid, objid, objsubid) as addr + FROM deps +) s +ORDER BY obj COLLATE "C", ident::text COLLATE "C"; + obj | ident | addr +----------------------------------------------------------+----------------------------------------------------------------------------+---------------------------------------------------------------------------- + edge e of property graph gt | ("property graph element",,,"e of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,e}",{}) + edge e of property graph gt | ("property graph element",,,"e of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,e}",{}) + edge e of property graph gt | ("property graph element",,,"e of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of property graph gt | ("property graph label",,,"e of create_property_graph_tests.gt") | ("property graph label","{create_property_graph_tests,gt,e}",{}) + label v1 of property graph gt | ("property graph label",,,"v1 of create_property_graph_tests.gt") | ("property graph label","{create_property_graph_tests,gt,v1}",{}) + label v1 of vertex v1 of property graph gt | ("property graph element label",,,"v1 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v1}",{}) + label v1 of vertex v1 of property graph gt | ("property graph element label",,,"v1 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v1}",{}) + label v2 of property graph gt | ("property graph label",,,"v2 of create_property_graph_tests.gt") | ("property graph label","{create_property_graph_tests,gt,v2}",{}) + label v2 of vertex v2 of property graph gt | ("property graph element label",,,"v2 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v2}",{}) + label v2 of vertex v2 of property graph gt | ("property graph element label",,,"v2 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v2}",{}) + property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property a of property graph gt | ("property graph property",,,"a of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,a}",{}) + property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property b of property graph gt | ("property graph property",,,"b of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,b}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of property graph gt | ("property graph property",,,"c of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,c}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of property graph gt | ("property graph property",,,"k1 of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,k1}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of property graph gt | ("property graph property",,,"k2 of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,k2}",{}) + property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property m of property graph gt | ("property graph property",,,"m of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,m}",{}) + property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property n of property graph gt | ("property graph property",,,"n of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,n}",{}) + type gt | (type,create_property_graph_tests,gt,create_property_graph_tests.gt) | (type,{create_property_graph_tests.gt},{}) + type gt[] | (type,create_property_graph_tests,_gt,create_property_graph_tests.gt[]) | (type,{create_property_graph_tests.gt[]},{}) + vertex v1 of property graph gt | ("property graph element",,,"v1 of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,v1}",{}) + vertex v2 of property graph gt | ("property graph element",,,"v2 of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,v2}",{}) +(52 rows) + \a\t SELECT pg_get_propgraphdef('g2'::regclass); CREATE PROPERTY GRAPH create_property_graph_tests.g2 diff --git a/src/test/regress/expected/event_trigger.out b/src/test/regress/expected/event_trigger.out index 065f586310f..ed8d5df397e 100644 --- a/src/test/regress/expected/event_trigger.out +++ b/src/test/regress/expected/event_trigger.out @@ -173,6 +173,23 @@ NOTICE: test_event_trigger: ddl_command_end CREATE USER MAPPING alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; NOTICE: test_event_trigger: ddl_command_end ALTER DEFAULT PRIVILEGES +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE TABLE t2x (i int PRIMARY KEY, j text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); +NOTICE: test_event_trigger: ddl_command_end CREATE PROPERTY GRAPH +DROP PROPERTY GRAPH gx; +NOTICE: test_event_trigger: ddl_command_end DROP PROPERTY GRAPH +DROP TABLE t1x, t2x; +NOTICE: test_event_trigger: ddl_command_end DROP TABLE -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; ERROR: permission denied to change owner of event trigger "regress_event_trigger" diff --git a/src/test/regress/expected/object_address.out b/src/test/regress/expected/object_address.out index 97227d67a54..5e53f0b092e 100644 --- a/src/test/regress/expected/object_address.out +++ b/src/test/regress/expected/object_address.out @@ -67,7 +67,9 @@ DECLARE BEGIN FOR objtype IN VALUES ('toast table'), ('index column'), ('sequence column'), ('toast table column'), ('view column'), ('materialized view column'), - ('property graph element'), ('property graph label'), ('property graph property') + ('property graph element'), ('property graph element label'), + ('property graph label'), ('property graph label property'), + ('property graph property') LOOP BEGIN PERFORM pg_get_object_address(objtype, '{one}', '{}'); @@ -84,7 +86,9 @@ WARNING: error for toast table column: unsupported object type "toast table col WARNING: error for view column: unsupported object type "view column" WARNING: error for materialized view column: unsupported object type "materialized view column" WARNING: error for property graph element: unsupported object type "property graph element" +WARNING: error for property graph element label: unrecognized object type "property graph element label" WARNING: error for property graph label: unsupported object type "property graph label" +WARNING: error for property graph label property: unrecognized object type "property graph label property" WARNING: error for property graph property: unsupported object type "property graph property" -- miscellaneous other errors select * from pg_get_object_address('operator of access method', '{btree,integer_ops,1}', '{int4,bool}'); @@ -593,7 +597,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace @@ -653,6 +659,8 @@ ORDER BY objects.classid, objects.objid, objects.objsubid; ("(""parameter ACL"",,,)")|("(""parameter ACL"",,)")|NULL ("(""property graph element"",,,)")|("(""property graph element"",,)")|NULL ("(""property graph label"",,,)")|("(""property graph label"",,)")|NULL +("(""property graph element label"",,,)")|("(""property graph element label"",,)")|NULL ("(""property graph property"",,,)")|("(""property graph property"",,)")|NULL +("(""property graph label property"",,,)")|("(""property graph label property"",,)")|NULL -- restore normal output mode \a\t diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..9608dd5c4af 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -298,6 +298,29 @@ SELECT (pg_identify_object(classid, objid, objsubid)).* refobjid = 'create_property_graph_tests.g2'::regclass ORDER BY 1, 2, 3, 4; +-- test object address functions with recursive dependency walk +-- covers all property graph object types including indirect dependents +SELECT * +FROM ( + WITH RECURSIVE deps (classid, objid, objsubid, refclassid, refobjid, refobjsubid) AS ( + SELECT classid, objid, objsubid, + refclassid, refobjid, refobjsubid + FROM pg_depend + WHERE refclassid = 'pg_class'::regclass AND + refobjid = 'create_property_graph_tests.gt'::regclass + UNION ALL + SELECT d.classid, d.objid, d.objsubid, + d.refclassid, d.refobjid, d.refobjsubid + FROM pg_depend d + JOIN deps dp ON d.refclassid = dp.classid AND d.refobjid = dp.objid AND d.refobjsubid = dp.objsubid + ) + SELECT pg_describe_object(classid, objid, objsubid) as obj, + pg_identify_object(classid, objid, objsubid) as ident, + pg_identify_object_as_address(classid, objid, objsubid) as addr + FROM deps +) s +ORDER BY obj COLLATE "C", ident::text COLLATE "C"; + \a\t SELECT pg_get_propgraphdef('g2'::regclass); SELECT pg_get_propgraphdef('g3'::regclass); diff --git a/src/test/regress/sql/event_trigger.sql b/src/test/regress/sql/event_trigger.sql index 32e9bb58c5e..271f443378b 100644 --- a/src/test/regress/sql/event_trigger.sql +++ b/src/test/regress/sql/event_trigger.sql @@ -143,6 +143,19 @@ create user mapping for regress_evt_user server useless_server; alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +CREATE TABLE t2x (i int PRIMARY KEY, j text); + +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); + +DROP PROPERTY GRAPH gx; +DROP TABLE t1x, t2x; + -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; diff --git a/src/test/regress/sql/object_address.sql b/src/test/regress/sql/object_address.sql index 1bbe9457c1c..27109d421c7 100644 --- a/src/test/regress/sql/object_address.sql +++ b/src/test/regress/sql/object_address.sql @@ -67,7 +67,9 @@ DECLARE BEGIN FOR objtype IN VALUES ('toast table'), ('index column'), ('sequence column'), ('toast table column'), ('view column'), ('materialized view column'), - ('property graph element'), ('property graph label'), ('property graph property') + ('property graph element'), ('property graph element label'), + ('property graph label'), ('property graph label property'), + ('property graph property') LOOP BEGIN PERFORM pg_get_object_address(objtype, '{one}', '{}'); @@ -282,7 +284,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace -- 2.34.1 --R84XrR4Hgw0dH3Ec-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v3] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-23 09:27 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-23 09:27 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing them to hit the default case and error out with "unsupported object class". During DROP PROPERTY GRAPH, this manifests when an event trigger is active, because pg_event_trigger_ddl_commands() calls these functions. The same code paths are also reachable via pg_identify_object() and pg_identify_object_as_address(). This commit adds the missing cases. Test coverage is added in object_address.sql for these two catalog types and in create_property_graph.sql covering all property graph object types. A test in event_trigger.sql verifies that DROP PROPERTY GRAPH works correctly when an event trigger is active. Author: Bertrand Drouvot <[email protected]> Reviewed-by: Michael Paquier <[email protected]> Reviewed-by: Ashutosh Bapat <[email protected]> Discussion: https://postgr.es/m/aej1DkLwhyZWmtxJ@bdtpg --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 78 ++++++++++++++++ src/test/regress/expected/event_trigger.out | 17 ++++ src/test/regress/expected/object_address.out | 10 +- .../regress/sql/create_property_graph.sql | 23 +++++ src/test/regress/sql/event_trigger.sql | 13 +++ src/test/regress/sql/object_address.sql | 6 +- 7 files changed, 238 insertions(+), 2 deletions(-) 14.7% src/backend/catalog/ 75.5% src/test/regress/expected/ 9.7% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..eb9e17fb727 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -752,6 +752,84 @@ SELECT (pg_identify_object(classid, objid, objsubid)).* type | create_property_graph_tests | g2 | create_property_graph_tests.g2 (21 rows) +-- test object address functions with recursive dependency walk +-- covers all property graph object types including indirect dependents +SELECT * +FROM ( + WITH RECURSIVE deps (classid, objid, objsubid, refclassid, refobjid, refobjsubid) AS ( + SELECT classid, objid, objsubid, + refclassid, refobjid, refobjsubid + FROM pg_depend + WHERE refclassid = 'pg_class'::regclass AND + refobjid = 'create_property_graph_tests.gt'::regclass + UNION ALL + SELECT d.classid, d.objid, d.objsubid, + d.refclassid, d.refobjid, d.refobjsubid + FROM pg_depend d + JOIN deps dp ON d.refclassid = dp.classid AND d.refobjid = dp.objid AND d.refobjsubid = dp.objsubid + ) + SELECT pg_describe_object(classid, objid, objsubid) as obj, + pg_identify_object(classid, objid, objsubid) as ident, + pg_identify_object_as_address(classid, objid, objsubid) as addr + FROM deps +) s +ORDER BY obj COLLATE "C", ident::text COLLATE "C"; + obj | ident | addr +----------------------------------------------------------+----------------------------------------------------------------------------+---------------------------------------------------------------------------- + edge e of property graph gt | ("property graph element",,,"e of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,e}",{}) + edge e of property graph gt | ("property graph element",,,"e of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,e}",{}) + edge e of property graph gt | ("property graph element",,,"e of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of property graph gt | ("property graph label",,,"e of create_property_graph_tests.gt") | ("property graph label","{create_property_graph_tests,gt,e}",{}) + label v1 of property graph gt | ("property graph label",,,"v1 of create_property_graph_tests.gt") | ("property graph label","{create_property_graph_tests,gt,v1}",{}) + label v1 of vertex v1 of property graph gt | ("property graph element label",,,"v1 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v1}",{}) + label v1 of vertex v1 of property graph gt | ("property graph element label",,,"v1 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v1}",{}) + label v2 of property graph gt | ("property graph label",,,"v2 of create_property_graph_tests.gt") | ("property graph label","{create_property_graph_tests,gt,v2}",{}) + label v2 of vertex v2 of property graph gt | ("property graph element label",,,"v2 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v2}",{}) + label v2 of vertex v2 of property graph gt | ("property graph element label",,,"v2 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v2}",{}) + property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property a of property graph gt | ("property graph property",,,"a of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,a}",{}) + property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property b of property graph gt | ("property graph property",,,"b of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,b}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of property graph gt | ("property graph property",,,"c of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,c}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of property graph gt | ("property graph property",,,"k1 of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,k1}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of property graph gt | ("property graph property",,,"k2 of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,k2}",{}) + property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property m of property graph gt | ("property graph property",,,"m of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,m}",{}) + property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property n of property graph gt | ("property graph property",,,"n of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,n}",{}) + type gt | (type,create_property_graph_tests,gt,create_property_graph_tests.gt) | (type,{create_property_graph_tests.gt},{}) + type gt[] | (type,create_property_graph_tests,_gt,create_property_graph_tests.gt[]) | (type,{create_property_graph_tests.gt[]},{}) + vertex v1 of property graph gt | ("property graph element",,,"v1 of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,v1}",{}) + vertex v2 of property graph gt | ("property graph element",,,"v2 of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,v2}",{}) +(52 rows) + \a\t SELECT pg_get_propgraphdef('g2'::regclass); CREATE PROPERTY GRAPH create_property_graph_tests.g2 diff --git a/src/test/regress/expected/event_trigger.out b/src/test/regress/expected/event_trigger.out index 065f586310f..ed8d5df397e 100644 --- a/src/test/regress/expected/event_trigger.out +++ b/src/test/regress/expected/event_trigger.out @@ -173,6 +173,23 @@ NOTICE: test_event_trigger: ddl_command_end CREATE USER MAPPING alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; NOTICE: test_event_trigger: ddl_command_end ALTER DEFAULT PRIVILEGES +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE TABLE t2x (i int PRIMARY KEY, j text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); +NOTICE: test_event_trigger: ddl_command_end CREATE PROPERTY GRAPH +DROP PROPERTY GRAPH gx; +NOTICE: test_event_trigger: ddl_command_end DROP PROPERTY GRAPH +DROP TABLE t1x, t2x; +NOTICE: test_event_trigger: ddl_command_end DROP TABLE -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; ERROR: permission denied to change owner of event trigger "regress_event_trigger" diff --git a/src/test/regress/expected/object_address.out b/src/test/regress/expected/object_address.out index 97227d67a54..5e53f0b092e 100644 --- a/src/test/regress/expected/object_address.out +++ b/src/test/regress/expected/object_address.out @@ -67,7 +67,9 @@ DECLARE BEGIN FOR objtype IN VALUES ('toast table'), ('index column'), ('sequence column'), ('toast table column'), ('view column'), ('materialized view column'), - ('property graph element'), ('property graph label'), ('property graph property') + ('property graph element'), ('property graph element label'), + ('property graph label'), ('property graph label property'), + ('property graph property') LOOP BEGIN PERFORM pg_get_object_address(objtype, '{one}', '{}'); @@ -84,7 +86,9 @@ WARNING: error for toast table column: unsupported object type "toast table col WARNING: error for view column: unsupported object type "view column" WARNING: error for materialized view column: unsupported object type "materialized view column" WARNING: error for property graph element: unsupported object type "property graph element" +WARNING: error for property graph element label: unrecognized object type "property graph element label" WARNING: error for property graph label: unsupported object type "property graph label" +WARNING: error for property graph label property: unrecognized object type "property graph label property" WARNING: error for property graph property: unsupported object type "property graph property" -- miscellaneous other errors select * from pg_get_object_address('operator of access method', '{btree,integer_ops,1}', '{int4,bool}'); @@ -593,7 +597,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace @@ -653,6 +659,8 @@ ORDER BY objects.classid, objects.objid, objects.objsubid; ("(""parameter ACL"",,,)")|("(""parameter ACL"",,)")|NULL ("(""property graph element"",,,)")|("(""property graph element"",,)")|NULL ("(""property graph label"",,,)")|("(""property graph label"",,)")|NULL +("(""property graph element label"",,,)")|("(""property graph element label"",,)")|NULL ("(""property graph property"",,,)")|("(""property graph property"",,)")|NULL +("(""property graph label property"",,,)")|("(""property graph label property"",,)")|NULL -- restore normal output mode \a\t diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..9608dd5c4af 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -298,6 +298,29 @@ SELECT (pg_identify_object(classid, objid, objsubid)).* refobjid = 'create_property_graph_tests.g2'::regclass ORDER BY 1, 2, 3, 4; +-- test object address functions with recursive dependency walk +-- covers all property graph object types including indirect dependents +SELECT * +FROM ( + WITH RECURSIVE deps (classid, objid, objsubid, refclassid, refobjid, refobjsubid) AS ( + SELECT classid, objid, objsubid, + refclassid, refobjid, refobjsubid + FROM pg_depend + WHERE refclassid = 'pg_class'::regclass AND + refobjid = 'create_property_graph_tests.gt'::regclass + UNION ALL + SELECT d.classid, d.objid, d.objsubid, + d.refclassid, d.refobjid, d.refobjsubid + FROM pg_depend d + JOIN deps dp ON d.refclassid = dp.classid AND d.refobjid = dp.objid AND d.refobjsubid = dp.objsubid + ) + SELECT pg_describe_object(classid, objid, objsubid) as obj, + pg_identify_object(classid, objid, objsubid) as ident, + pg_identify_object_as_address(classid, objid, objsubid) as addr + FROM deps +) s +ORDER BY obj COLLATE "C", ident::text COLLATE "C"; + \a\t SELECT pg_get_propgraphdef('g2'::regclass); SELECT pg_get_propgraphdef('g3'::regclass); diff --git a/src/test/regress/sql/event_trigger.sql b/src/test/regress/sql/event_trigger.sql index 32e9bb58c5e..271f443378b 100644 --- a/src/test/regress/sql/event_trigger.sql +++ b/src/test/regress/sql/event_trigger.sql @@ -143,6 +143,19 @@ create user mapping for regress_evt_user server useless_server; alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +CREATE TABLE t2x (i int PRIMARY KEY, j text); + +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); + +DROP PROPERTY GRAPH gx; +DROP TABLE t1x, t2x; + -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; diff --git a/src/test/regress/sql/object_address.sql b/src/test/regress/sql/object_address.sql index 1bbe9457c1c..27109d421c7 100644 --- a/src/test/regress/sql/object_address.sql +++ b/src/test/regress/sql/object_address.sql @@ -67,7 +67,9 @@ DECLARE BEGIN FOR objtype IN VALUES ('toast table'), ('index column'), ('sequence column'), ('toast table column'), ('view column'), ('materialized view column'), - ('property graph element'), ('property graph label'), ('property graph property') + ('property graph element'), ('property graph element label'), + ('property graph label'), ('property graph label property'), + ('property graph property') LOOP BEGIN PERFORM pg_get_object_address(objtype, '{one}', '{}'); @@ -282,7 +284,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace -- 2.34.1 --R84XrR4Hgw0dH3Ec-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v3] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-23 09:27 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-23 09:27 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing them to hit the default case and error out with "unsupported object class". During DROP PROPERTY GRAPH, this manifests when an event trigger is active, because pg_event_trigger_ddl_commands() calls these functions. The same code paths are also reachable via pg_identify_object() and pg_identify_object_as_address(). This commit adds the missing cases. Test coverage is added in object_address.sql for these two catalog types and in create_property_graph.sql covering all property graph object types. A test in event_trigger.sql verifies that DROP PROPERTY GRAPH works correctly when an event trigger is active. Author: Bertrand Drouvot <[email protected]> Reviewed-by: Michael Paquier <[email protected]> Reviewed-by: Ashutosh Bapat <[email protected]> Discussion: https://postgr.es/m/aej1DkLwhyZWmtxJ@bdtpg --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 78 ++++++++++++++++ src/test/regress/expected/event_trigger.out | 17 ++++ src/test/regress/expected/object_address.out | 10 +- .../regress/sql/create_property_graph.sql | 23 +++++ src/test/regress/sql/event_trigger.sql | 13 +++ src/test/regress/sql/object_address.sql | 6 +- 7 files changed, 238 insertions(+), 2 deletions(-) 14.7% src/backend/catalog/ 75.5% src/test/regress/expected/ 9.7% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..eb9e17fb727 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -752,6 +752,84 @@ SELECT (pg_identify_object(classid, objid, objsubid)).* type | create_property_graph_tests | g2 | create_property_graph_tests.g2 (21 rows) +-- test object address functions with recursive dependency walk +-- covers all property graph object types including indirect dependents +SELECT * +FROM ( + WITH RECURSIVE deps (classid, objid, objsubid, refclassid, refobjid, refobjsubid) AS ( + SELECT classid, objid, objsubid, + refclassid, refobjid, refobjsubid + FROM pg_depend + WHERE refclassid = 'pg_class'::regclass AND + refobjid = 'create_property_graph_tests.gt'::regclass + UNION ALL + SELECT d.classid, d.objid, d.objsubid, + d.refclassid, d.refobjid, d.refobjsubid + FROM pg_depend d + JOIN deps dp ON d.refclassid = dp.classid AND d.refobjid = dp.objid AND d.refobjsubid = dp.objsubid + ) + SELECT pg_describe_object(classid, objid, objsubid) as obj, + pg_identify_object(classid, objid, objsubid) as ident, + pg_identify_object_as_address(classid, objid, objsubid) as addr + FROM deps +) s +ORDER BY obj COLLATE "C", ident::text COLLATE "C"; + obj | ident | addr +----------------------------------------------------------+----------------------------------------------------------------------------+---------------------------------------------------------------------------- + edge e of property graph gt | ("property graph element",,,"e of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,e}",{}) + edge e of property graph gt | ("property graph element",,,"e of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,e}",{}) + edge e of property graph gt | ("property graph element",,,"e of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of property graph gt | ("property graph label",,,"e of create_property_graph_tests.gt") | ("property graph label","{create_property_graph_tests,gt,e}",{}) + label v1 of property graph gt | ("property graph label",,,"v1 of create_property_graph_tests.gt") | ("property graph label","{create_property_graph_tests,gt,v1}",{}) + label v1 of vertex v1 of property graph gt | ("property graph element label",,,"v1 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v1}",{}) + label v1 of vertex v1 of property graph gt | ("property graph element label",,,"v1 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v1}",{}) + label v2 of property graph gt | ("property graph label",,,"v2 of create_property_graph_tests.gt") | ("property graph label","{create_property_graph_tests,gt,v2}",{}) + label v2 of vertex v2 of property graph gt | ("property graph element label",,,"v2 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v2}",{}) + label v2 of vertex v2 of property graph gt | ("property graph element label",,,"v2 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v2}",{}) + property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property a of property graph gt | ("property graph property",,,"a of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,a}",{}) + property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property b of property graph gt | ("property graph property",,,"b of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,b}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of property graph gt | ("property graph property",,,"c of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,c}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of property graph gt | ("property graph property",,,"k1 of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,k1}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of property graph gt | ("property graph property",,,"k2 of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,k2}",{}) + property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property m of property graph gt | ("property graph property",,,"m of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,m}",{}) + property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property n of property graph gt | ("property graph property",,,"n of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,n}",{}) + type gt | (type,create_property_graph_tests,gt,create_property_graph_tests.gt) | (type,{create_property_graph_tests.gt},{}) + type gt[] | (type,create_property_graph_tests,_gt,create_property_graph_tests.gt[]) | (type,{create_property_graph_tests.gt[]},{}) + vertex v1 of property graph gt | ("property graph element",,,"v1 of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,v1}",{}) + vertex v2 of property graph gt | ("property graph element",,,"v2 of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,v2}",{}) +(52 rows) + \a\t SELECT pg_get_propgraphdef('g2'::regclass); CREATE PROPERTY GRAPH create_property_graph_tests.g2 diff --git a/src/test/regress/expected/event_trigger.out b/src/test/regress/expected/event_trigger.out index 065f586310f..ed8d5df397e 100644 --- a/src/test/regress/expected/event_trigger.out +++ b/src/test/regress/expected/event_trigger.out @@ -173,6 +173,23 @@ NOTICE: test_event_trigger: ddl_command_end CREATE USER MAPPING alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; NOTICE: test_event_trigger: ddl_command_end ALTER DEFAULT PRIVILEGES +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE TABLE t2x (i int PRIMARY KEY, j text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); +NOTICE: test_event_trigger: ddl_command_end CREATE PROPERTY GRAPH +DROP PROPERTY GRAPH gx; +NOTICE: test_event_trigger: ddl_command_end DROP PROPERTY GRAPH +DROP TABLE t1x, t2x; +NOTICE: test_event_trigger: ddl_command_end DROP TABLE -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; ERROR: permission denied to change owner of event trigger "regress_event_trigger" diff --git a/src/test/regress/expected/object_address.out b/src/test/regress/expected/object_address.out index 97227d67a54..5e53f0b092e 100644 --- a/src/test/regress/expected/object_address.out +++ b/src/test/regress/expected/object_address.out @@ -67,7 +67,9 @@ DECLARE BEGIN FOR objtype IN VALUES ('toast table'), ('index column'), ('sequence column'), ('toast table column'), ('view column'), ('materialized view column'), - ('property graph element'), ('property graph label'), ('property graph property') + ('property graph element'), ('property graph element label'), + ('property graph label'), ('property graph label property'), + ('property graph property') LOOP BEGIN PERFORM pg_get_object_address(objtype, '{one}', '{}'); @@ -84,7 +86,9 @@ WARNING: error for toast table column: unsupported object type "toast table col WARNING: error for view column: unsupported object type "view column" WARNING: error for materialized view column: unsupported object type "materialized view column" WARNING: error for property graph element: unsupported object type "property graph element" +WARNING: error for property graph element label: unrecognized object type "property graph element label" WARNING: error for property graph label: unsupported object type "property graph label" +WARNING: error for property graph label property: unrecognized object type "property graph label property" WARNING: error for property graph property: unsupported object type "property graph property" -- miscellaneous other errors select * from pg_get_object_address('operator of access method', '{btree,integer_ops,1}', '{int4,bool}'); @@ -593,7 +597,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace @@ -653,6 +659,8 @@ ORDER BY objects.classid, objects.objid, objects.objsubid; ("(""parameter ACL"",,,)")|("(""parameter ACL"",,)")|NULL ("(""property graph element"",,,)")|("(""property graph element"",,)")|NULL ("(""property graph label"",,,)")|("(""property graph label"",,)")|NULL +("(""property graph element label"",,,)")|("(""property graph element label"",,)")|NULL ("(""property graph property"",,,)")|("(""property graph property"",,)")|NULL +("(""property graph label property"",,,)")|("(""property graph label property"",,)")|NULL -- restore normal output mode \a\t diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..9608dd5c4af 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -298,6 +298,29 @@ SELECT (pg_identify_object(classid, objid, objsubid)).* refobjid = 'create_property_graph_tests.g2'::regclass ORDER BY 1, 2, 3, 4; +-- test object address functions with recursive dependency walk +-- covers all property graph object types including indirect dependents +SELECT * +FROM ( + WITH RECURSIVE deps (classid, objid, objsubid, refclassid, refobjid, refobjsubid) AS ( + SELECT classid, objid, objsubid, + refclassid, refobjid, refobjsubid + FROM pg_depend + WHERE refclassid = 'pg_class'::regclass AND + refobjid = 'create_property_graph_tests.gt'::regclass + UNION ALL + SELECT d.classid, d.objid, d.objsubid, + d.refclassid, d.refobjid, d.refobjsubid + FROM pg_depend d + JOIN deps dp ON d.refclassid = dp.classid AND d.refobjid = dp.objid AND d.refobjsubid = dp.objsubid + ) + SELECT pg_describe_object(classid, objid, objsubid) as obj, + pg_identify_object(classid, objid, objsubid) as ident, + pg_identify_object_as_address(classid, objid, objsubid) as addr + FROM deps +) s +ORDER BY obj COLLATE "C", ident::text COLLATE "C"; + \a\t SELECT pg_get_propgraphdef('g2'::regclass); SELECT pg_get_propgraphdef('g3'::regclass); diff --git a/src/test/regress/sql/event_trigger.sql b/src/test/regress/sql/event_trigger.sql index 32e9bb58c5e..271f443378b 100644 --- a/src/test/regress/sql/event_trigger.sql +++ b/src/test/regress/sql/event_trigger.sql @@ -143,6 +143,19 @@ create user mapping for regress_evt_user server useless_server; alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +CREATE TABLE t2x (i int PRIMARY KEY, j text); + +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); + +DROP PROPERTY GRAPH gx; +DROP TABLE t1x, t2x; + -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; diff --git a/src/test/regress/sql/object_address.sql b/src/test/regress/sql/object_address.sql index 1bbe9457c1c..27109d421c7 100644 --- a/src/test/regress/sql/object_address.sql +++ b/src/test/regress/sql/object_address.sql @@ -67,7 +67,9 @@ DECLARE BEGIN FOR objtype IN VALUES ('toast table'), ('index column'), ('sequence column'), ('toast table column'), ('view column'), ('materialized view column'), - ('property graph element'), ('property graph label'), ('property graph property') + ('property graph element'), ('property graph element label'), + ('property graph label'), ('property graph label property'), + ('property graph property') LOOP BEGIN PERFORM pg_get_object_address(objtype, '{one}', '{}'); @@ -282,7 +284,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace -- 2.34.1 --R84XrR4Hgw0dH3Ec-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v3] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-23 09:27 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-23 09:27 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing them to hit the default case and error out with "unsupported object class". During DROP PROPERTY GRAPH, this manifests when an event trigger is active, because pg_event_trigger_ddl_commands() calls these functions. The same code paths are also reachable via pg_identify_object() and pg_identify_object_as_address(). This commit adds the missing cases. Test coverage is added in object_address.sql for these two catalog types and in create_property_graph.sql covering all property graph object types. A test in event_trigger.sql verifies that DROP PROPERTY GRAPH works correctly when an event trigger is active. Author: Bertrand Drouvot <[email protected]> Reviewed-by: Michael Paquier <[email protected]> Reviewed-by: Ashutosh Bapat <[email protected]> Discussion: https://postgr.es/m/aej1DkLwhyZWmtxJ@bdtpg --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 78 ++++++++++++++++ src/test/regress/expected/event_trigger.out | 17 ++++ src/test/regress/expected/object_address.out | 10 +- .../regress/sql/create_property_graph.sql | 23 +++++ src/test/regress/sql/event_trigger.sql | 13 +++ src/test/regress/sql/object_address.sql | 6 +- 7 files changed, 238 insertions(+), 2 deletions(-) 14.7% src/backend/catalog/ 75.5% src/test/regress/expected/ 9.7% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..eb9e17fb727 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -752,6 +752,84 @@ SELECT (pg_identify_object(classid, objid, objsubid)).* type | create_property_graph_tests | g2 | create_property_graph_tests.g2 (21 rows) +-- test object address functions with recursive dependency walk +-- covers all property graph object types including indirect dependents +SELECT * +FROM ( + WITH RECURSIVE deps (classid, objid, objsubid, refclassid, refobjid, refobjsubid) AS ( + SELECT classid, objid, objsubid, + refclassid, refobjid, refobjsubid + FROM pg_depend + WHERE refclassid = 'pg_class'::regclass AND + refobjid = 'create_property_graph_tests.gt'::regclass + UNION ALL + SELECT d.classid, d.objid, d.objsubid, + d.refclassid, d.refobjid, d.refobjsubid + FROM pg_depend d + JOIN deps dp ON d.refclassid = dp.classid AND d.refobjid = dp.objid AND d.refobjsubid = dp.objsubid + ) + SELECT pg_describe_object(classid, objid, objsubid) as obj, + pg_identify_object(classid, objid, objsubid) as ident, + pg_identify_object_as_address(classid, objid, objsubid) as addr + FROM deps +) s +ORDER BY obj COLLATE "C", ident::text COLLATE "C"; + obj | ident | addr +----------------------------------------------------------+----------------------------------------------------------------------------+---------------------------------------------------------------------------- + edge e of property graph gt | ("property graph element",,,"e of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,e}",{}) + edge e of property graph gt | ("property graph element",,,"e of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,e}",{}) + edge e of property graph gt | ("property graph element",,,"e of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of property graph gt | ("property graph label",,,"e of create_property_graph_tests.gt") | ("property graph label","{create_property_graph_tests,gt,e}",{}) + label v1 of property graph gt | ("property graph label",,,"v1 of create_property_graph_tests.gt") | ("property graph label","{create_property_graph_tests,gt,v1}",{}) + label v1 of vertex v1 of property graph gt | ("property graph element label",,,"v1 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v1}",{}) + label v1 of vertex v1 of property graph gt | ("property graph element label",,,"v1 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v1}",{}) + label v2 of property graph gt | ("property graph label",,,"v2 of create_property_graph_tests.gt") | ("property graph label","{create_property_graph_tests,gt,v2}",{}) + label v2 of vertex v2 of property graph gt | ("property graph element label",,,"v2 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v2}",{}) + label v2 of vertex v2 of property graph gt | ("property graph element label",,,"v2 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v2}",{}) + property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property a of property graph gt | ("property graph property",,,"a of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,a}",{}) + property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property b of property graph gt | ("property graph property",,,"b of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,b}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of property graph gt | ("property graph property",,,"c of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,c}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of property graph gt | ("property graph property",,,"k1 of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,k1}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of property graph gt | ("property graph property",,,"k2 of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,k2}",{}) + property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property m of property graph gt | ("property graph property",,,"m of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,m}",{}) + property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property n of property graph gt | ("property graph property",,,"n of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,n}",{}) + type gt | (type,create_property_graph_tests,gt,create_property_graph_tests.gt) | (type,{create_property_graph_tests.gt},{}) + type gt[] | (type,create_property_graph_tests,_gt,create_property_graph_tests.gt[]) | (type,{create_property_graph_tests.gt[]},{}) + vertex v1 of property graph gt | ("property graph element",,,"v1 of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,v1}",{}) + vertex v2 of property graph gt | ("property graph element",,,"v2 of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,v2}",{}) +(52 rows) + \a\t SELECT pg_get_propgraphdef('g2'::regclass); CREATE PROPERTY GRAPH create_property_graph_tests.g2 diff --git a/src/test/regress/expected/event_trigger.out b/src/test/regress/expected/event_trigger.out index 065f586310f..ed8d5df397e 100644 --- a/src/test/regress/expected/event_trigger.out +++ b/src/test/regress/expected/event_trigger.out @@ -173,6 +173,23 @@ NOTICE: test_event_trigger: ddl_command_end CREATE USER MAPPING alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; NOTICE: test_event_trigger: ddl_command_end ALTER DEFAULT PRIVILEGES +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE TABLE t2x (i int PRIMARY KEY, j text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); +NOTICE: test_event_trigger: ddl_command_end CREATE PROPERTY GRAPH +DROP PROPERTY GRAPH gx; +NOTICE: test_event_trigger: ddl_command_end DROP PROPERTY GRAPH +DROP TABLE t1x, t2x; +NOTICE: test_event_trigger: ddl_command_end DROP TABLE -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; ERROR: permission denied to change owner of event trigger "regress_event_trigger" diff --git a/src/test/regress/expected/object_address.out b/src/test/regress/expected/object_address.out index 97227d67a54..5e53f0b092e 100644 --- a/src/test/regress/expected/object_address.out +++ b/src/test/regress/expected/object_address.out @@ -67,7 +67,9 @@ DECLARE BEGIN FOR objtype IN VALUES ('toast table'), ('index column'), ('sequence column'), ('toast table column'), ('view column'), ('materialized view column'), - ('property graph element'), ('property graph label'), ('property graph property') + ('property graph element'), ('property graph element label'), + ('property graph label'), ('property graph label property'), + ('property graph property') LOOP BEGIN PERFORM pg_get_object_address(objtype, '{one}', '{}'); @@ -84,7 +86,9 @@ WARNING: error for toast table column: unsupported object type "toast table col WARNING: error for view column: unsupported object type "view column" WARNING: error for materialized view column: unsupported object type "materialized view column" WARNING: error for property graph element: unsupported object type "property graph element" +WARNING: error for property graph element label: unrecognized object type "property graph element label" WARNING: error for property graph label: unsupported object type "property graph label" +WARNING: error for property graph label property: unrecognized object type "property graph label property" WARNING: error for property graph property: unsupported object type "property graph property" -- miscellaneous other errors select * from pg_get_object_address('operator of access method', '{btree,integer_ops,1}', '{int4,bool}'); @@ -593,7 +597,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace @@ -653,6 +659,8 @@ ORDER BY objects.classid, objects.objid, objects.objsubid; ("(""parameter ACL"",,,)")|("(""parameter ACL"",,)")|NULL ("(""property graph element"",,,)")|("(""property graph element"",,)")|NULL ("(""property graph label"",,,)")|("(""property graph label"",,)")|NULL +("(""property graph element label"",,,)")|("(""property graph element label"",,)")|NULL ("(""property graph property"",,,)")|("(""property graph property"",,)")|NULL +("(""property graph label property"",,,)")|("(""property graph label property"",,)")|NULL -- restore normal output mode \a\t diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..9608dd5c4af 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -298,6 +298,29 @@ SELECT (pg_identify_object(classid, objid, objsubid)).* refobjid = 'create_property_graph_tests.g2'::regclass ORDER BY 1, 2, 3, 4; +-- test object address functions with recursive dependency walk +-- covers all property graph object types including indirect dependents +SELECT * +FROM ( + WITH RECURSIVE deps (classid, objid, objsubid, refclassid, refobjid, refobjsubid) AS ( + SELECT classid, objid, objsubid, + refclassid, refobjid, refobjsubid + FROM pg_depend + WHERE refclassid = 'pg_class'::regclass AND + refobjid = 'create_property_graph_tests.gt'::regclass + UNION ALL + SELECT d.classid, d.objid, d.objsubid, + d.refclassid, d.refobjid, d.refobjsubid + FROM pg_depend d + JOIN deps dp ON d.refclassid = dp.classid AND d.refobjid = dp.objid AND d.refobjsubid = dp.objsubid + ) + SELECT pg_describe_object(classid, objid, objsubid) as obj, + pg_identify_object(classid, objid, objsubid) as ident, + pg_identify_object_as_address(classid, objid, objsubid) as addr + FROM deps +) s +ORDER BY obj COLLATE "C", ident::text COLLATE "C"; + \a\t SELECT pg_get_propgraphdef('g2'::regclass); SELECT pg_get_propgraphdef('g3'::regclass); diff --git a/src/test/regress/sql/event_trigger.sql b/src/test/regress/sql/event_trigger.sql index 32e9bb58c5e..271f443378b 100644 --- a/src/test/regress/sql/event_trigger.sql +++ b/src/test/regress/sql/event_trigger.sql @@ -143,6 +143,19 @@ create user mapping for regress_evt_user server useless_server; alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +CREATE TABLE t2x (i int PRIMARY KEY, j text); + +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); + +DROP PROPERTY GRAPH gx; +DROP TABLE t1x, t2x; + -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; diff --git a/src/test/regress/sql/object_address.sql b/src/test/regress/sql/object_address.sql index 1bbe9457c1c..27109d421c7 100644 --- a/src/test/regress/sql/object_address.sql +++ b/src/test/regress/sql/object_address.sql @@ -67,7 +67,9 @@ DECLARE BEGIN FOR objtype IN VALUES ('toast table'), ('index column'), ('sequence column'), ('toast table column'), ('view column'), ('materialized view column'), - ('property graph element'), ('property graph label'), ('property graph property') + ('property graph element'), ('property graph element label'), + ('property graph label'), ('property graph label property'), + ('property graph property') LOOP BEGIN PERFORM pg_get_object_address(objtype, '{one}', '{}'); @@ -282,7 +284,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace -- 2.34.1 --R84XrR4Hgw0dH3Ec-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v2] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-23 09:27 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-23 09:27 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing them to hit the default case and error out with "unsupported object class". During DROP PROPERTY GRAPH, this manifests when an event trigger is active, because pg_event_trigger_ddl_commands() calls these functions. The same code paths are also reachable via pg_identify_object() and pg_identify_object_as_address(). This commit adds the missing cases. Test coverage is added in object_address.sql for these two catalog types via the zero-OID test that exercises pg_identify_object() and pg_identify_object_as_address(). A test in event_trigger.sql verifies that DROP PROPERTY GRAPH works correctly when an event trigger is active. Author: Bertrand Drouvot <[email protected]> Reviewed-by: Michael Paquier <[email protected]> Reviewed-by: Ashutosh Bapat <[email protected]> Discussion: https://postgr.es/m/aej1DkLwhyZWmtxJ@bdtpg --- src/backend/catalog/objectaddress.c | 93 ++++++++++++++++++++ src/test/regress/expected/event_trigger.out | 17 ++++ src/test/regress/expected/object_address.out | 4 + src/test/regress/sql/event_trigger.sql | 13 +++ src/test/regress/sql/object_address.sql | 2 + 5 files changed, 129 insertions(+) 62.4% src/backend/catalog/ 25.6% src/test/regress/expected/ 11.8% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/event_trigger.out b/src/test/regress/expected/event_trigger.out index 065f586310f..ed8d5df397e 100644 --- a/src/test/regress/expected/event_trigger.out +++ b/src/test/regress/expected/event_trigger.out @@ -173,6 +173,23 @@ NOTICE: test_event_trigger: ddl_command_end CREATE USER MAPPING alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; NOTICE: test_event_trigger: ddl_command_end ALTER DEFAULT PRIVILEGES +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE TABLE t2x (i int PRIMARY KEY, j text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); +NOTICE: test_event_trigger: ddl_command_end CREATE PROPERTY GRAPH +DROP PROPERTY GRAPH gx; +NOTICE: test_event_trigger: ddl_command_end DROP PROPERTY GRAPH +DROP TABLE t1x, t2x; +NOTICE: test_event_trigger: ddl_command_end DROP TABLE -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; ERROR: permission denied to change owner of event trigger "regress_event_trigger" diff --git a/src/test/regress/expected/object_address.out b/src/test/regress/expected/object_address.out index 97227d67a54..729c3537f25 100644 --- a/src/test/regress/expected/object_address.out +++ b/src/test/regress/expected/object_address.out @@ -593,7 +593,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace @@ -653,6 +655,8 @@ ORDER BY objects.classid, objects.objid, objects.objsubid; ("(""parameter ACL"",,,)")|("(""parameter ACL"",,)")|NULL ("(""property graph element"",,,)")|("(""property graph element"",,)")|NULL ("(""property graph label"",,,)")|("(""property graph label"",,)")|NULL +("(""property graph element label"",,,)")|("(""property graph element label"",,)")|NULL ("(""property graph property"",,,)")|("(""property graph property"",,)")|NULL +("(""property graph label property"",,,)")|("(""property graph label property"",,)")|NULL -- restore normal output mode \a\t diff --git a/src/test/regress/sql/event_trigger.sql b/src/test/regress/sql/event_trigger.sql index 32e9bb58c5e..271f443378b 100644 --- a/src/test/regress/sql/event_trigger.sql +++ b/src/test/regress/sql/event_trigger.sql @@ -143,6 +143,19 @@ create user mapping for regress_evt_user server useless_server; alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +CREATE TABLE t2x (i int PRIMARY KEY, j text); + +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); + +DROP PROPERTY GRAPH gx; +DROP TABLE t1x, t2x; + -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; diff --git a/src/test/regress/sql/object_address.sql b/src/test/regress/sql/object_address.sql index 1bbe9457c1c..620dacf1045 100644 --- a/src/test/regress/sql/object_address.sql +++ b/src/test/regress/sql/object_address.sql @@ -282,7 +282,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace -- 2.34.1 --gtUR827Uq8d5gVsQ-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v2] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-23 09:27 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-23 09:27 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing them to hit the default case and error out with "unsupported object class". During DROP PROPERTY GRAPH, this manifests when an event trigger is active, because pg_event_trigger_ddl_commands() calls these functions. The same code paths are also reachable via pg_identify_object() and pg_identify_object_as_address(). This commit adds the missing cases. Test coverage is added in object_address.sql for these two catalog types via the zero-OID test that exercises pg_identify_object() and pg_identify_object_as_address(). A test in event_trigger.sql verifies that DROP PROPERTY GRAPH works correctly when an event trigger is active. Author: Bertrand Drouvot <[email protected]> Reviewed-by: Michael Paquier <[email protected]> Reviewed-by: Ashutosh Bapat <[email protected]> Discussion: https://postgr.es/m/aej1DkLwhyZWmtxJ@bdtpg --- src/backend/catalog/objectaddress.c | 93 ++++++++++++++++++++ src/test/regress/expected/event_trigger.out | 17 ++++ src/test/regress/expected/object_address.out | 4 + src/test/regress/sql/event_trigger.sql | 13 +++ src/test/regress/sql/object_address.sql | 2 + 5 files changed, 129 insertions(+) 62.4% src/backend/catalog/ 25.6% src/test/regress/expected/ 11.8% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/event_trigger.out b/src/test/regress/expected/event_trigger.out index 065f586310f..ed8d5df397e 100644 --- a/src/test/regress/expected/event_trigger.out +++ b/src/test/regress/expected/event_trigger.out @@ -173,6 +173,23 @@ NOTICE: test_event_trigger: ddl_command_end CREATE USER MAPPING alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; NOTICE: test_event_trigger: ddl_command_end ALTER DEFAULT PRIVILEGES +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE TABLE t2x (i int PRIMARY KEY, j text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); +NOTICE: test_event_trigger: ddl_command_end CREATE PROPERTY GRAPH +DROP PROPERTY GRAPH gx; +NOTICE: test_event_trigger: ddl_command_end DROP PROPERTY GRAPH +DROP TABLE t1x, t2x; +NOTICE: test_event_trigger: ddl_command_end DROP TABLE -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; ERROR: permission denied to change owner of event trigger "regress_event_trigger" diff --git a/src/test/regress/expected/object_address.out b/src/test/regress/expected/object_address.out index 97227d67a54..729c3537f25 100644 --- a/src/test/regress/expected/object_address.out +++ b/src/test/regress/expected/object_address.out @@ -593,7 +593,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace @@ -653,6 +655,8 @@ ORDER BY objects.classid, objects.objid, objects.objsubid; ("(""parameter ACL"",,,)")|("(""parameter ACL"",,)")|NULL ("(""property graph element"",,,)")|("(""property graph element"",,)")|NULL ("(""property graph label"",,,)")|("(""property graph label"",,)")|NULL +("(""property graph element label"",,,)")|("(""property graph element label"",,)")|NULL ("(""property graph property"",,,)")|("(""property graph property"",,)")|NULL +("(""property graph label property"",,,)")|("(""property graph label property"",,)")|NULL -- restore normal output mode \a\t diff --git a/src/test/regress/sql/event_trigger.sql b/src/test/regress/sql/event_trigger.sql index 32e9bb58c5e..271f443378b 100644 --- a/src/test/regress/sql/event_trigger.sql +++ b/src/test/regress/sql/event_trigger.sql @@ -143,6 +143,19 @@ create user mapping for regress_evt_user server useless_server; alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +CREATE TABLE t2x (i int PRIMARY KEY, j text); + +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); + +DROP PROPERTY GRAPH gx; +DROP TABLE t1x, t2x; + -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; diff --git a/src/test/regress/sql/object_address.sql b/src/test/regress/sql/object_address.sql index 1bbe9457c1c..620dacf1045 100644 --- a/src/test/regress/sql/object_address.sql +++ b/src/test/regress/sql/object_address.sql @@ -282,7 +282,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace -- 2.34.1 --gtUR827Uq8d5gVsQ-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v3] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-23 09:27 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-23 09:27 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing them to hit the default case and error out with "unsupported object class". During DROP PROPERTY GRAPH, this manifests when an event trigger is active, because pg_event_trigger_ddl_commands() calls these functions. The same code paths are also reachable via pg_identify_object() and pg_identify_object_as_address(). This commit adds the missing cases. Test coverage is added in object_address.sql for these two catalog types and in create_property_graph.sql covering all property graph object types. A test in event_trigger.sql verifies that DROP PROPERTY GRAPH works correctly when an event trigger is active. Author: Bertrand Drouvot <[email protected]> Reviewed-by: Michael Paquier <[email protected]> Reviewed-by: Ashutosh Bapat <[email protected]> Discussion: https://postgr.es/m/aej1DkLwhyZWmtxJ@bdtpg --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 78 ++++++++++++++++ src/test/regress/expected/event_trigger.out | 17 ++++ src/test/regress/expected/object_address.out | 10 +- .../regress/sql/create_property_graph.sql | 23 +++++ src/test/regress/sql/event_trigger.sql | 13 +++ src/test/regress/sql/object_address.sql | 6 +- 7 files changed, 238 insertions(+), 2 deletions(-) 14.7% src/backend/catalog/ 75.5% src/test/regress/expected/ 9.7% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..eb9e17fb727 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -752,6 +752,84 @@ SELECT (pg_identify_object(classid, objid, objsubid)).* type | create_property_graph_tests | g2 | create_property_graph_tests.g2 (21 rows) +-- test object address functions with recursive dependency walk +-- covers all property graph object types including indirect dependents +SELECT * +FROM ( + WITH RECURSIVE deps (classid, objid, objsubid, refclassid, refobjid, refobjsubid) AS ( + SELECT classid, objid, objsubid, + refclassid, refobjid, refobjsubid + FROM pg_depend + WHERE refclassid = 'pg_class'::regclass AND + refobjid = 'create_property_graph_tests.gt'::regclass + UNION ALL + SELECT d.classid, d.objid, d.objsubid, + d.refclassid, d.refobjid, d.refobjsubid + FROM pg_depend d + JOIN deps dp ON d.refclassid = dp.classid AND d.refobjid = dp.objid AND d.refobjsubid = dp.objsubid + ) + SELECT pg_describe_object(classid, objid, objsubid) as obj, + pg_identify_object(classid, objid, objsubid) as ident, + pg_identify_object_as_address(classid, objid, objsubid) as addr + FROM deps +) s +ORDER BY obj COLLATE "C", ident::text COLLATE "C"; + obj | ident | addr +----------------------------------------------------------+----------------------------------------------------------------------------+---------------------------------------------------------------------------- + edge e of property graph gt | ("property graph element",,,"e of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,e}",{}) + edge e of property graph gt | ("property graph element",,,"e of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,e}",{}) + edge e of property graph gt | ("property graph element",,,"e of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of property graph gt | ("property graph label",,,"e of create_property_graph_tests.gt") | ("property graph label","{create_property_graph_tests,gt,e}",{}) + label v1 of property graph gt | ("property graph label",,,"v1 of create_property_graph_tests.gt") | ("property graph label","{create_property_graph_tests,gt,v1}",{}) + label v1 of vertex v1 of property graph gt | ("property graph element label",,,"v1 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v1}",{}) + label v1 of vertex v1 of property graph gt | ("property graph element label",,,"v1 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v1}",{}) + label v2 of property graph gt | ("property graph label",,,"v2 of create_property_graph_tests.gt") | ("property graph label","{create_property_graph_tests,gt,v2}",{}) + label v2 of vertex v2 of property graph gt | ("property graph element label",,,"v2 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v2}",{}) + label v2 of vertex v2 of property graph gt | ("property graph element label",,,"v2 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v2}",{}) + property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property a of property graph gt | ("property graph property",,,"a of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,a}",{}) + property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property b of property graph gt | ("property graph property",,,"b of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,b}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of property graph gt | ("property graph property",,,"c of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,c}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of property graph gt | ("property graph property",,,"k1 of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,k1}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of property graph gt | ("property graph property",,,"k2 of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,k2}",{}) + property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property m of property graph gt | ("property graph property",,,"m of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,m}",{}) + property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property n of property graph gt | ("property graph property",,,"n of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,n}",{}) + type gt | (type,create_property_graph_tests,gt,create_property_graph_tests.gt) | (type,{create_property_graph_tests.gt},{}) + type gt[] | (type,create_property_graph_tests,_gt,create_property_graph_tests.gt[]) | (type,{create_property_graph_tests.gt[]},{}) + vertex v1 of property graph gt | ("property graph element",,,"v1 of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,v1}",{}) + vertex v2 of property graph gt | ("property graph element",,,"v2 of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,v2}",{}) +(52 rows) + \a\t SELECT pg_get_propgraphdef('g2'::regclass); CREATE PROPERTY GRAPH create_property_graph_tests.g2 diff --git a/src/test/regress/expected/event_trigger.out b/src/test/regress/expected/event_trigger.out index 065f586310f..ed8d5df397e 100644 --- a/src/test/regress/expected/event_trigger.out +++ b/src/test/regress/expected/event_trigger.out @@ -173,6 +173,23 @@ NOTICE: test_event_trigger: ddl_command_end CREATE USER MAPPING alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; NOTICE: test_event_trigger: ddl_command_end ALTER DEFAULT PRIVILEGES +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE TABLE t2x (i int PRIMARY KEY, j text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); +NOTICE: test_event_trigger: ddl_command_end CREATE PROPERTY GRAPH +DROP PROPERTY GRAPH gx; +NOTICE: test_event_trigger: ddl_command_end DROP PROPERTY GRAPH +DROP TABLE t1x, t2x; +NOTICE: test_event_trigger: ddl_command_end DROP TABLE -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; ERROR: permission denied to change owner of event trigger "regress_event_trigger" diff --git a/src/test/regress/expected/object_address.out b/src/test/regress/expected/object_address.out index 97227d67a54..5e53f0b092e 100644 --- a/src/test/regress/expected/object_address.out +++ b/src/test/regress/expected/object_address.out @@ -67,7 +67,9 @@ DECLARE BEGIN FOR objtype IN VALUES ('toast table'), ('index column'), ('sequence column'), ('toast table column'), ('view column'), ('materialized view column'), - ('property graph element'), ('property graph label'), ('property graph property') + ('property graph element'), ('property graph element label'), + ('property graph label'), ('property graph label property'), + ('property graph property') LOOP BEGIN PERFORM pg_get_object_address(objtype, '{one}', '{}'); @@ -84,7 +86,9 @@ WARNING: error for toast table column: unsupported object type "toast table col WARNING: error for view column: unsupported object type "view column" WARNING: error for materialized view column: unsupported object type "materialized view column" WARNING: error for property graph element: unsupported object type "property graph element" +WARNING: error for property graph element label: unrecognized object type "property graph element label" WARNING: error for property graph label: unsupported object type "property graph label" +WARNING: error for property graph label property: unrecognized object type "property graph label property" WARNING: error for property graph property: unsupported object type "property graph property" -- miscellaneous other errors select * from pg_get_object_address('operator of access method', '{btree,integer_ops,1}', '{int4,bool}'); @@ -593,7 +597,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace @@ -653,6 +659,8 @@ ORDER BY objects.classid, objects.objid, objects.objsubid; ("(""parameter ACL"",,,)")|("(""parameter ACL"",,)")|NULL ("(""property graph element"",,,)")|("(""property graph element"",,)")|NULL ("(""property graph label"",,,)")|("(""property graph label"",,)")|NULL +("(""property graph element label"",,,)")|("(""property graph element label"",,)")|NULL ("(""property graph property"",,,)")|("(""property graph property"",,)")|NULL +("(""property graph label property"",,,)")|("(""property graph label property"",,)")|NULL -- restore normal output mode \a\t diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..9608dd5c4af 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -298,6 +298,29 @@ SELECT (pg_identify_object(classid, objid, objsubid)).* refobjid = 'create_property_graph_tests.g2'::regclass ORDER BY 1, 2, 3, 4; +-- test object address functions with recursive dependency walk +-- covers all property graph object types including indirect dependents +SELECT * +FROM ( + WITH RECURSIVE deps (classid, objid, objsubid, refclassid, refobjid, refobjsubid) AS ( + SELECT classid, objid, objsubid, + refclassid, refobjid, refobjsubid + FROM pg_depend + WHERE refclassid = 'pg_class'::regclass AND + refobjid = 'create_property_graph_tests.gt'::regclass + UNION ALL + SELECT d.classid, d.objid, d.objsubid, + d.refclassid, d.refobjid, d.refobjsubid + FROM pg_depend d + JOIN deps dp ON d.refclassid = dp.classid AND d.refobjid = dp.objid AND d.refobjsubid = dp.objsubid + ) + SELECT pg_describe_object(classid, objid, objsubid) as obj, + pg_identify_object(classid, objid, objsubid) as ident, + pg_identify_object_as_address(classid, objid, objsubid) as addr + FROM deps +) s +ORDER BY obj COLLATE "C", ident::text COLLATE "C"; + \a\t SELECT pg_get_propgraphdef('g2'::regclass); SELECT pg_get_propgraphdef('g3'::regclass); diff --git a/src/test/regress/sql/event_trigger.sql b/src/test/regress/sql/event_trigger.sql index 32e9bb58c5e..271f443378b 100644 --- a/src/test/regress/sql/event_trigger.sql +++ b/src/test/regress/sql/event_trigger.sql @@ -143,6 +143,19 @@ create user mapping for regress_evt_user server useless_server; alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +CREATE TABLE t2x (i int PRIMARY KEY, j text); + +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); + +DROP PROPERTY GRAPH gx; +DROP TABLE t1x, t2x; + -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; diff --git a/src/test/regress/sql/object_address.sql b/src/test/regress/sql/object_address.sql index 1bbe9457c1c..27109d421c7 100644 --- a/src/test/regress/sql/object_address.sql +++ b/src/test/regress/sql/object_address.sql @@ -67,7 +67,9 @@ DECLARE BEGIN FOR objtype IN VALUES ('toast table'), ('index column'), ('sequence column'), ('toast table column'), ('view column'), ('materialized view column'), - ('property graph element'), ('property graph label'), ('property graph property') + ('property graph element'), ('property graph element label'), + ('property graph label'), ('property graph label property'), + ('property graph property') LOOP BEGIN PERFORM pg_get_object_address(objtype, '{one}', '{}'); @@ -282,7 +284,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace -- 2.34.1 --R84XrR4Hgw0dH3Ec-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v2] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-23 09:27 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-23 09:27 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing them to hit the default case and error out with "unsupported object class". During DROP PROPERTY GRAPH, this manifests when an event trigger is active, because pg_event_trigger_ddl_commands() calls these functions. The same code paths are also reachable via pg_identify_object() and pg_identify_object_as_address(). This commit adds the missing cases. Test coverage is added in object_address.sql for these two catalog types via the zero-OID test that exercises pg_identify_object() and pg_identify_object_as_address(). A test in event_trigger.sql verifies that DROP PROPERTY GRAPH works correctly when an event trigger is active. Author: Bertrand Drouvot <[email protected]> Reviewed-by: Michael Paquier <[email protected]> Reviewed-by: Ashutosh Bapat <[email protected]> Discussion: https://postgr.es/m/aej1DkLwhyZWmtxJ@bdtpg --- src/backend/catalog/objectaddress.c | 93 ++++++++++++++++++++ src/test/regress/expected/event_trigger.out | 17 ++++ src/test/regress/expected/object_address.out | 4 + src/test/regress/sql/event_trigger.sql | 13 +++ src/test/regress/sql/object_address.sql | 2 + 5 files changed, 129 insertions(+) 62.4% src/backend/catalog/ 25.6% src/test/regress/expected/ 11.8% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/event_trigger.out b/src/test/regress/expected/event_trigger.out index 065f586310f..ed8d5df397e 100644 --- a/src/test/regress/expected/event_trigger.out +++ b/src/test/regress/expected/event_trigger.out @@ -173,6 +173,23 @@ NOTICE: test_event_trigger: ddl_command_end CREATE USER MAPPING alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; NOTICE: test_event_trigger: ddl_command_end ALTER DEFAULT PRIVILEGES +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE TABLE t2x (i int PRIMARY KEY, j text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); +NOTICE: test_event_trigger: ddl_command_end CREATE PROPERTY GRAPH +DROP PROPERTY GRAPH gx; +NOTICE: test_event_trigger: ddl_command_end DROP PROPERTY GRAPH +DROP TABLE t1x, t2x; +NOTICE: test_event_trigger: ddl_command_end DROP TABLE -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; ERROR: permission denied to change owner of event trigger "regress_event_trigger" diff --git a/src/test/regress/expected/object_address.out b/src/test/regress/expected/object_address.out index 97227d67a54..729c3537f25 100644 --- a/src/test/regress/expected/object_address.out +++ b/src/test/regress/expected/object_address.out @@ -593,7 +593,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace @@ -653,6 +655,8 @@ ORDER BY objects.classid, objects.objid, objects.objsubid; ("(""parameter ACL"",,,)")|("(""parameter ACL"",,)")|NULL ("(""property graph element"",,,)")|("(""property graph element"",,)")|NULL ("(""property graph label"",,,)")|("(""property graph label"",,)")|NULL +("(""property graph element label"",,,)")|("(""property graph element label"",,)")|NULL ("(""property graph property"",,,)")|("(""property graph property"",,)")|NULL +("(""property graph label property"",,,)")|("(""property graph label property"",,)")|NULL -- restore normal output mode \a\t diff --git a/src/test/regress/sql/event_trigger.sql b/src/test/regress/sql/event_trigger.sql index 32e9bb58c5e..271f443378b 100644 --- a/src/test/regress/sql/event_trigger.sql +++ b/src/test/regress/sql/event_trigger.sql @@ -143,6 +143,19 @@ create user mapping for regress_evt_user server useless_server; alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +CREATE TABLE t2x (i int PRIMARY KEY, j text); + +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); + +DROP PROPERTY GRAPH gx; +DROP TABLE t1x, t2x; + -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; diff --git a/src/test/regress/sql/object_address.sql b/src/test/regress/sql/object_address.sql index 1bbe9457c1c..620dacf1045 100644 --- a/src/test/regress/sql/object_address.sql +++ b/src/test/regress/sql/object_address.sql @@ -282,7 +282,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace -- 2.34.1 --gtUR827Uq8d5gVsQ-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v3] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-23 09:27 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-23 09:27 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing them to hit the default case and error out with "unsupported object class". During DROP PROPERTY GRAPH, this manifests when an event trigger is active, because pg_event_trigger_ddl_commands() calls these functions. The same code paths are also reachable via pg_identify_object() and pg_identify_object_as_address(). This commit adds the missing cases. Test coverage is added in object_address.sql for these two catalog types and in create_property_graph.sql covering all property graph object types. A test in event_trigger.sql verifies that DROP PROPERTY GRAPH works correctly when an event trigger is active. Author: Bertrand Drouvot <[email protected]> Reviewed-by: Michael Paquier <[email protected]> Reviewed-by: Ashutosh Bapat <[email protected]> Discussion: https://postgr.es/m/aej1DkLwhyZWmtxJ@bdtpg --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 78 ++++++++++++++++ src/test/regress/expected/event_trigger.out | 17 ++++ src/test/regress/expected/object_address.out | 10 +- .../regress/sql/create_property_graph.sql | 23 +++++ src/test/regress/sql/event_trigger.sql | 13 +++ src/test/regress/sql/object_address.sql | 6 +- 7 files changed, 238 insertions(+), 2 deletions(-) 14.7% src/backend/catalog/ 75.5% src/test/regress/expected/ 9.7% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..eb9e17fb727 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -752,6 +752,84 @@ SELECT (pg_identify_object(classid, objid, objsubid)).* type | create_property_graph_tests | g2 | create_property_graph_tests.g2 (21 rows) +-- test object address functions with recursive dependency walk +-- covers all property graph object types including indirect dependents +SELECT * +FROM ( + WITH RECURSIVE deps (classid, objid, objsubid, refclassid, refobjid, refobjsubid) AS ( + SELECT classid, objid, objsubid, + refclassid, refobjid, refobjsubid + FROM pg_depend + WHERE refclassid = 'pg_class'::regclass AND + refobjid = 'create_property_graph_tests.gt'::regclass + UNION ALL + SELECT d.classid, d.objid, d.objsubid, + d.refclassid, d.refobjid, d.refobjsubid + FROM pg_depend d + JOIN deps dp ON d.refclassid = dp.classid AND d.refobjid = dp.objid AND d.refobjsubid = dp.objsubid + ) + SELECT pg_describe_object(classid, objid, objsubid) as obj, + pg_identify_object(classid, objid, objsubid) as ident, + pg_identify_object_as_address(classid, objid, objsubid) as addr + FROM deps +) s +ORDER BY obj COLLATE "C", ident::text COLLATE "C"; + obj | ident | addr +----------------------------------------------------------+----------------------------------------------------------------------------+---------------------------------------------------------------------------- + edge e of property graph gt | ("property graph element",,,"e of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,e}",{}) + edge e of property graph gt | ("property graph element",,,"e of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,e}",{}) + edge e of property graph gt | ("property graph element",,,"e of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of property graph gt | ("property graph label",,,"e of create_property_graph_tests.gt") | ("property graph label","{create_property_graph_tests,gt,e}",{}) + label v1 of property graph gt | ("property graph label",,,"v1 of create_property_graph_tests.gt") | ("property graph label","{create_property_graph_tests,gt,v1}",{}) + label v1 of vertex v1 of property graph gt | ("property graph element label",,,"v1 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v1}",{}) + label v1 of vertex v1 of property graph gt | ("property graph element label",,,"v1 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v1}",{}) + label v2 of property graph gt | ("property graph label",,,"v2 of create_property_graph_tests.gt") | ("property graph label","{create_property_graph_tests,gt,v2}",{}) + label v2 of vertex v2 of property graph gt | ("property graph element label",,,"v2 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v2}",{}) + label v2 of vertex v2 of property graph gt | ("property graph element label",,,"v2 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v2}",{}) + property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property a of property graph gt | ("property graph property",,,"a of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,a}",{}) + property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property b of property graph gt | ("property graph property",,,"b of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,b}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of property graph gt | ("property graph property",,,"c of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,c}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of property graph gt | ("property graph property",,,"k1 of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,k1}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of property graph gt | ("property graph property",,,"k2 of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,k2}",{}) + property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property m of property graph gt | ("property graph property",,,"m of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,m}",{}) + property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property n of property graph gt | ("property graph property",,,"n of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,n}",{}) + type gt | (type,create_property_graph_tests,gt,create_property_graph_tests.gt) | (type,{create_property_graph_tests.gt},{}) + type gt[] | (type,create_property_graph_tests,_gt,create_property_graph_tests.gt[]) | (type,{create_property_graph_tests.gt[]},{}) + vertex v1 of property graph gt | ("property graph element",,,"v1 of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,v1}",{}) + vertex v2 of property graph gt | ("property graph element",,,"v2 of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,v2}",{}) +(52 rows) + \a\t SELECT pg_get_propgraphdef('g2'::regclass); CREATE PROPERTY GRAPH create_property_graph_tests.g2 diff --git a/src/test/regress/expected/event_trigger.out b/src/test/regress/expected/event_trigger.out index 065f586310f..ed8d5df397e 100644 --- a/src/test/regress/expected/event_trigger.out +++ b/src/test/regress/expected/event_trigger.out @@ -173,6 +173,23 @@ NOTICE: test_event_trigger: ddl_command_end CREATE USER MAPPING alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; NOTICE: test_event_trigger: ddl_command_end ALTER DEFAULT PRIVILEGES +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE TABLE t2x (i int PRIMARY KEY, j text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); +NOTICE: test_event_trigger: ddl_command_end CREATE PROPERTY GRAPH +DROP PROPERTY GRAPH gx; +NOTICE: test_event_trigger: ddl_command_end DROP PROPERTY GRAPH +DROP TABLE t1x, t2x; +NOTICE: test_event_trigger: ddl_command_end DROP TABLE -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; ERROR: permission denied to change owner of event trigger "regress_event_trigger" diff --git a/src/test/regress/expected/object_address.out b/src/test/regress/expected/object_address.out index 97227d67a54..5e53f0b092e 100644 --- a/src/test/regress/expected/object_address.out +++ b/src/test/regress/expected/object_address.out @@ -67,7 +67,9 @@ DECLARE BEGIN FOR objtype IN VALUES ('toast table'), ('index column'), ('sequence column'), ('toast table column'), ('view column'), ('materialized view column'), - ('property graph element'), ('property graph label'), ('property graph property') + ('property graph element'), ('property graph element label'), + ('property graph label'), ('property graph label property'), + ('property graph property') LOOP BEGIN PERFORM pg_get_object_address(objtype, '{one}', '{}'); @@ -84,7 +86,9 @@ WARNING: error for toast table column: unsupported object type "toast table col WARNING: error for view column: unsupported object type "view column" WARNING: error for materialized view column: unsupported object type "materialized view column" WARNING: error for property graph element: unsupported object type "property graph element" +WARNING: error for property graph element label: unrecognized object type "property graph element label" WARNING: error for property graph label: unsupported object type "property graph label" +WARNING: error for property graph label property: unrecognized object type "property graph label property" WARNING: error for property graph property: unsupported object type "property graph property" -- miscellaneous other errors select * from pg_get_object_address('operator of access method', '{btree,integer_ops,1}', '{int4,bool}'); @@ -593,7 +597,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace @@ -653,6 +659,8 @@ ORDER BY objects.classid, objects.objid, objects.objsubid; ("(""parameter ACL"",,,)")|("(""parameter ACL"",,)")|NULL ("(""property graph element"",,,)")|("(""property graph element"",,)")|NULL ("(""property graph label"",,,)")|("(""property graph label"",,)")|NULL +("(""property graph element label"",,,)")|("(""property graph element label"",,)")|NULL ("(""property graph property"",,,)")|("(""property graph property"",,)")|NULL +("(""property graph label property"",,,)")|("(""property graph label property"",,)")|NULL -- restore normal output mode \a\t diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..9608dd5c4af 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -298,6 +298,29 @@ SELECT (pg_identify_object(classid, objid, objsubid)).* refobjid = 'create_property_graph_tests.g2'::regclass ORDER BY 1, 2, 3, 4; +-- test object address functions with recursive dependency walk +-- covers all property graph object types including indirect dependents +SELECT * +FROM ( + WITH RECURSIVE deps (classid, objid, objsubid, refclassid, refobjid, refobjsubid) AS ( + SELECT classid, objid, objsubid, + refclassid, refobjid, refobjsubid + FROM pg_depend + WHERE refclassid = 'pg_class'::regclass AND + refobjid = 'create_property_graph_tests.gt'::regclass + UNION ALL + SELECT d.classid, d.objid, d.objsubid, + d.refclassid, d.refobjid, d.refobjsubid + FROM pg_depend d + JOIN deps dp ON d.refclassid = dp.classid AND d.refobjid = dp.objid AND d.refobjsubid = dp.objsubid + ) + SELECT pg_describe_object(classid, objid, objsubid) as obj, + pg_identify_object(classid, objid, objsubid) as ident, + pg_identify_object_as_address(classid, objid, objsubid) as addr + FROM deps +) s +ORDER BY obj COLLATE "C", ident::text COLLATE "C"; + \a\t SELECT pg_get_propgraphdef('g2'::regclass); SELECT pg_get_propgraphdef('g3'::regclass); diff --git a/src/test/regress/sql/event_trigger.sql b/src/test/regress/sql/event_trigger.sql index 32e9bb58c5e..271f443378b 100644 --- a/src/test/regress/sql/event_trigger.sql +++ b/src/test/regress/sql/event_trigger.sql @@ -143,6 +143,19 @@ create user mapping for regress_evt_user server useless_server; alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +CREATE TABLE t2x (i int PRIMARY KEY, j text); + +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); + +DROP PROPERTY GRAPH gx; +DROP TABLE t1x, t2x; + -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; diff --git a/src/test/regress/sql/object_address.sql b/src/test/regress/sql/object_address.sql index 1bbe9457c1c..27109d421c7 100644 --- a/src/test/regress/sql/object_address.sql +++ b/src/test/regress/sql/object_address.sql @@ -67,7 +67,9 @@ DECLARE BEGIN FOR objtype IN VALUES ('toast table'), ('index column'), ('sequence column'), ('toast table column'), ('view column'), ('materialized view column'), - ('property graph element'), ('property graph label'), ('property graph property') + ('property graph element'), ('property graph element label'), + ('property graph label'), ('property graph label property'), + ('property graph property') LOOP BEGIN PERFORM pg_get_object_address(objtype, '{one}', '{}'); @@ -282,7 +284,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace -- 2.34.1 --R84XrR4Hgw0dH3Ec-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v2] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-23 09:27 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-23 09:27 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing them to hit the default case and error out with "unsupported object class". During DROP PROPERTY GRAPH, this manifests when an event trigger is active, because pg_event_trigger_ddl_commands() calls these functions. The same code paths are also reachable via pg_identify_object() and pg_identify_object_as_address(). This commit adds the missing cases. Test coverage is added in object_address.sql for these two catalog types via the zero-OID test that exercises pg_identify_object() and pg_identify_object_as_address(). A test in event_trigger.sql verifies that DROP PROPERTY GRAPH works correctly when an event trigger is active. Author: Bertrand Drouvot <[email protected]> Reviewed-by: Michael Paquier <[email protected]> Reviewed-by: Ashutosh Bapat <[email protected]> Discussion: https://postgr.es/m/aej1DkLwhyZWmtxJ@bdtpg --- src/backend/catalog/objectaddress.c | 93 ++++++++++++++++++++ src/test/regress/expected/event_trigger.out | 17 ++++ src/test/regress/expected/object_address.out | 4 + src/test/regress/sql/event_trigger.sql | 13 +++ src/test/regress/sql/object_address.sql | 2 + 5 files changed, 129 insertions(+) 62.4% src/backend/catalog/ 25.6% src/test/regress/expected/ 11.8% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/event_trigger.out b/src/test/regress/expected/event_trigger.out index 065f586310f..ed8d5df397e 100644 --- a/src/test/regress/expected/event_trigger.out +++ b/src/test/regress/expected/event_trigger.out @@ -173,6 +173,23 @@ NOTICE: test_event_trigger: ddl_command_end CREATE USER MAPPING alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; NOTICE: test_event_trigger: ddl_command_end ALTER DEFAULT PRIVILEGES +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE TABLE t2x (i int PRIMARY KEY, j text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); +NOTICE: test_event_trigger: ddl_command_end CREATE PROPERTY GRAPH +DROP PROPERTY GRAPH gx; +NOTICE: test_event_trigger: ddl_command_end DROP PROPERTY GRAPH +DROP TABLE t1x, t2x; +NOTICE: test_event_trigger: ddl_command_end DROP TABLE -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; ERROR: permission denied to change owner of event trigger "regress_event_trigger" diff --git a/src/test/regress/expected/object_address.out b/src/test/regress/expected/object_address.out index 97227d67a54..729c3537f25 100644 --- a/src/test/regress/expected/object_address.out +++ b/src/test/regress/expected/object_address.out @@ -593,7 +593,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace @@ -653,6 +655,8 @@ ORDER BY objects.classid, objects.objid, objects.objsubid; ("(""parameter ACL"",,,)")|("(""parameter ACL"",,)")|NULL ("(""property graph element"",,,)")|("(""property graph element"",,)")|NULL ("(""property graph label"",,,)")|("(""property graph label"",,)")|NULL +("(""property graph element label"",,,)")|("(""property graph element label"",,)")|NULL ("(""property graph property"",,,)")|("(""property graph property"",,)")|NULL +("(""property graph label property"",,,)")|("(""property graph label property"",,)")|NULL -- restore normal output mode \a\t diff --git a/src/test/regress/sql/event_trigger.sql b/src/test/regress/sql/event_trigger.sql index 32e9bb58c5e..271f443378b 100644 --- a/src/test/regress/sql/event_trigger.sql +++ b/src/test/regress/sql/event_trigger.sql @@ -143,6 +143,19 @@ create user mapping for regress_evt_user server useless_server; alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +CREATE TABLE t2x (i int PRIMARY KEY, j text); + +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); + +DROP PROPERTY GRAPH gx; +DROP TABLE t1x, t2x; + -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; diff --git a/src/test/regress/sql/object_address.sql b/src/test/regress/sql/object_address.sql index 1bbe9457c1c..620dacf1045 100644 --- a/src/test/regress/sql/object_address.sql +++ b/src/test/regress/sql/object_address.sql @@ -282,7 +282,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace -- 2.34.1 --gtUR827Uq8d5gVsQ-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v3] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-23 09:27 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-23 09:27 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing them to hit the default case and error out with "unsupported object class". During DROP PROPERTY GRAPH, this manifests when an event trigger is active, because pg_event_trigger_ddl_commands() calls these functions. The same code paths are also reachable via pg_identify_object() and pg_identify_object_as_address(). This commit adds the missing cases. Test coverage is added in object_address.sql for these two catalog types and in create_property_graph.sql covering all property graph object types. A test in event_trigger.sql verifies that DROP PROPERTY GRAPH works correctly when an event trigger is active. Author: Bertrand Drouvot <[email protected]> Reviewed-by: Michael Paquier <[email protected]> Reviewed-by: Ashutosh Bapat <[email protected]> Discussion: https://postgr.es/m/aej1DkLwhyZWmtxJ@bdtpg --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 78 ++++++++++++++++ src/test/regress/expected/event_trigger.out | 17 ++++ src/test/regress/expected/object_address.out | 10 +- .../regress/sql/create_property_graph.sql | 23 +++++ src/test/regress/sql/event_trigger.sql | 13 +++ src/test/regress/sql/object_address.sql | 6 +- 7 files changed, 238 insertions(+), 2 deletions(-) 14.7% src/backend/catalog/ 75.5% src/test/regress/expected/ 9.7% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..eb9e17fb727 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -752,6 +752,84 @@ SELECT (pg_identify_object(classid, objid, objsubid)).* type | create_property_graph_tests | g2 | create_property_graph_tests.g2 (21 rows) +-- test object address functions with recursive dependency walk +-- covers all property graph object types including indirect dependents +SELECT * +FROM ( + WITH RECURSIVE deps (classid, objid, objsubid, refclassid, refobjid, refobjsubid) AS ( + SELECT classid, objid, objsubid, + refclassid, refobjid, refobjsubid + FROM pg_depend + WHERE refclassid = 'pg_class'::regclass AND + refobjid = 'create_property_graph_tests.gt'::regclass + UNION ALL + SELECT d.classid, d.objid, d.objsubid, + d.refclassid, d.refobjid, d.refobjsubid + FROM pg_depend d + JOIN deps dp ON d.refclassid = dp.classid AND d.refobjid = dp.objid AND d.refobjsubid = dp.objsubid + ) + SELECT pg_describe_object(classid, objid, objsubid) as obj, + pg_identify_object(classid, objid, objsubid) as ident, + pg_identify_object_as_address(classid, objid, objsubid) as addr + FROM deps +) s +ORDER BY obj COLLATE "C", ident::text COLLATE "C"; + obj | ident | addr +----------------------------------------------------------+----------------------------------------------------------------------------+---------------------------------------------------------------------------- + edge e of property graph gt | ("property graph element",,,"e of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,e}",{}) + edge e of property graph gt | ("property graph element",,,"e of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,e}",{}) + edge e of property graph gt | ("property graph element",,,"e of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of property graph gt | ("property graph label",,,"e of create_property_graph_tests.gt") | ("property graph label","{create_property_graph_tests,gt,e}",{}) + label v1 of property graph gt | ("property graph label",,,"v1 of create_property_graph_tests.gt") | ("property graph label","{create_property_graph_tests,gt,v1}",{}) + label v1 of vertex v1 of property graph gt | ("property graph element label",,,"v1 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v1}",{}) + label v1 of vertex v1 of property graph gt | ("property graph element label",,,"v1 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v1}",{}) + label v2 of property graph gt | ("property graph label",,,"v2 of create_property_graph_tests.gt") | ("property graph label","{create_property_graph_tests,gt,v2}",{}) + label v2 of vertex v2 of property graph gt | ("property graph element label",,,"v2 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v2}",{}) + label v2 of vertex v2 of property graph gt | ("property graph element label",,,"v2 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v2}",{}) + property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property a of property graph gt | ("property graph property",,,"a of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,a}",{}) + property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property b of property graph gt | ("property graph property",,,"b of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,b}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of property graph gt | ("property graph property",,,"c of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,c}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of property graph gt | ("property graph property",,,"k1 of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,k1}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of property graph gt | ("property graph property",,,"k2 of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,k2}",{}) + property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property m of property graph gt | ("property graph property",,,"m of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,m}",{}) + property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property n of property graph gt | ("property graph property",,,"n of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,n}",{}) + type gt | (type,create_property_graph_tests,gt,create_property_graph_tests.gt) | (type,{create_property_graph_tests.gt},{}) + type gt[] | (type,create_property_graph_tests,_gt,create_property_graph_tests.gt[]) | (type,{create_property_graph_tests.gt[]},{}) + vertex v1 of property graph gt | ("property graph element",,,"v1 of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,v1}",{}) + vertex v2 of property graph gt | ("property graph element",,,"v2 of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,v2}",{}) +(52 rows) + \a\t SELECT pg_get_propgraphdef('g2'::regclass); CREATE PROPERTY GRAPH create_property_graph_tests.g2 diff --git a/src/test/regress/expected/event_trigger.out b/src/test/regress/expected/event_trigger.out index 065f586310f..ed8d5df397e 100644 --- a/src/test/regress/expected/event_trigger.out +++ b/src/test/regress/expected/event_trigger.out @@ -173,6 +173,23 @@ NOTICE: test_event_trigger: ddl_command_end CREATE USER MAPPING alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; NOTICE: test_event_trigger: ddl_command_end ALTER DEFAULT PRIVILEGES +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE TABLE t2x (i int PRIMARY KEY, j text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); +NOTICE: test_event_trigger: ddl_command_end CREATE PROPERTY GRAPH +DROP PROPERTY GRAPH gx; +NOTICE: test_event_trigger: ddl_command_end DROP PROPERTY GRAPH +DROP TABLE t1x, t2x; +NOTICE: test_event_trigger: ddl_command_end DROP TABLE -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; ERROR: permission denied to change owner of event trigger "regress_event_trigger" diff --git a/src/test/regress/expected/object_address.out b/src/test/regress/expected/object_address.out index 97227d67a54..5e53f0b092e 100644 --- a/src/test/regress/expected/object_address.out +++ b/src/test/regress/expected/object_address.out @@ -67,7 +67,9 @@ DECLARE BEGIN FOR objtype IN VALUES ('toast table'), ('index column'), ('sequence column'), ('toast table column'), ('view column'), ('materialized view column'), - ('property graph element'), ('property graph label'), ('property graph property') + ('property graph element'), ('property graph element label'), + ('property graph label'), ('property graph label property'), + ('property graph property') LOOP BEGIN PERFORM pg_get_object_address(objtype, '{one}', '{}'); @@ -84,7 +86,9 @@ WARNING: error for toast table column: unsupported object type "toast table col WARNING: error for view column: unsupported object type "view column" WARNING: error for materialized view column: unsupported object type "materialized view column" WARNING: error for property graph element: unsupported object type "property graph element" +WARNING: error for property graph element label: unrecognized object type "property graph element label" WARNING: error for property graph label: unsupported object type "property graph label" +WARNING: error for property graph label property: unrecognized object type "property graph label property" WARNING: error for property graph property: unsupported object type "property graph property" -- miscellaneous other errors select * from pg_get_object_address('operator of access method', '{btree,integer_ops,1}', '{int4,bool}'); @@ -593,7 +597,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace @@ -653,6 +659,8 @@ ORDER BY objects.classid, objects.objid, objects.objsubid; ("(""parameter ACL"",,,)")|("(""parameter ACL"",,)")|NULL ("(""property graph element"",,,)")|("(""property graph element"",,)")|NULL ("(""property graph label"",,,)")|("(""property graph label"",,)")|NULL +("(""property graph element label"",,,)")|("(""property graph element label"",,)")|NULL ("(""property graph property"",,,)")|("(""property graph property"",,)")|NULL +("(""property graph label property"",,,)")|("(""property graph label property"",,)")|NULL -- restore normal output mode \a\t diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..9608dd5c4af 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -298,6 +298,29 @@ SELECT (pg_identify_object(classid, objid, objsubid)).* refobjid = 'create_property_graph_tests.g2'::regclass ORDER BY 1, 2, 3, 4; +-- test object address functions with recursive dependency walk +-- covers all property graph object types including indirect dependents +SELECT * +FROM ( + WITH RECURSIVE deps (classid, objid, objsubid, refclassid, refobjid, refobjsubid) AS ( + SELECT classid, objid, objsubid, + refclassid, refobjid, refobjsubid + FROM pg_depend + WHERE refclassid = 'pg_class'::regclass AND + refobjid = 'create_property_graph_tests.gt'::regclass + UNION ALL + SELECT d.classid, d.objid, d.objsubid, + d.refclassid, d.refobjid, d.refobjsubid + FROM pg_depend d + JOIN deps dp ON d.refclassid = dp.classid AND d.refobjid = dp.objid AND d.refobjsubid = dp.objsubid + ) + SELECT pg_describe_object(classid, objid, objsubid) as obj, + pg_identify_object(classid, objid, objsubid) as ident, + pg_identify_object_as_address(classid, objid, objsubid) as addr + FROM deps +) s +ORDER BY obj COLLATE "C", ident::text COLLATE "C"; + \a\t SELECT pg_get_propgraphdef('g2'::regclass); SELECT pg_get_propgraphdef('g3'::regclass); diff --git a/src/test/regress/sql/event_trigger.sql b/src/test/regress/sql/event_trigger.sql index 32e9bb58c5e..271f443378b 100644 --- a/src/test/regress/sql/event_trigger.sql +++ b/src/test/regress/sql/event_trigger.sql @@ -143,6 +143,19 @@ create user mapping for regress_evt_user server useless_server; alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +CREATE TABLE t2x (i int PRIMARY KEY, j text); + +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); + +DROP PROPERTY GRAPH gx; +DROP TABLE t1x, t2x; + -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; diff --git a/src/test/regress/sql/object_address.sql b/src/test/regress/sql/object_address.sql index 1bbe9457c1c..27109d421c7 100644 --- a/src/test/regress/sql/object_address.sql +++ b/src/test/regress/sql/object_address.sql @@ -67,7 +67,9 @@ DECLARE BEGIN FOR objtype IN VALUES ('toast table'), ('index column'), ('sequence column'), ('toast table column'), ('view column'), ('materialized view column'), - ('property graph element'), ('property graph label'), ('property graph property') + ('property graph element'), ('property graph element label'), + ('property graph label'), ('property graph label property'), + ('property graph property') LOOP BEGIN PERFORM pg_get_object_address(objtype, '{one}', '{}'); @@ -282,7 +284,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace -- 2.34.1 --R84XrR4Hgw0dH3Ec-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v3] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-23 09:27 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-23 09:27 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing them to hit the default case and error out with "unsupported object class". During DROP PROPERTY GRAPH, this manifests when an event trigger is active, because pg_event_trigger_ddl_commands() calls these functions. The same code paths are also reachable via pg_identify_object() and pg_identify_object_as_address(). This commit adds the missing cases. Test coverage is added in object_address.sql for these two catalog types and in create_property_graph.sql covering all property graph object types. A test in event_trigger.sql verifies that DROP PROPERTY GRAPH works correctly when an event trigger is active. Author: Bertrand Drouvot <[email protected]> Reviewed-by: Michael Paquier <[email protected]> Reviewed-by: Ashutosh Bapat <[email protected]> Discussion: https://postgr.es/m/aej1DkLwhyZWmtxJ@bdtpg --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 78 ++++++++++++++++ src/test/regress/expected/event_trigger.out | 17 ++++ src/test/regress/expected/object_address.out | 10 +- .../regress/sql/create_property_graph.sql | 23 +++++ src/test/regress/sql/event_trigger.sql | 13 +++ src/test/regress/sql/object_address.sql | 6 +- 7 files changed, 238 insertions(+), 2 deletions(-) 14.7% src/backend/catalog/ 75.5% src/test/regress/expected/ 9.7% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..eb9e17fb727 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -752,6 +752,84 @@ SELECT (pg_identify_object(classid, objid, objsubid)).* type | create_property_graph_tests | g2 | create_property_graph_tests.g2 (21 rows) +-- test object address functions with recursive dependency walk +-- covers all property graph object types including indirect dependents +SELECT * +FROM ( + WITH RECURSIVE deps (classid, objid, objsubid, refclassid, refobjid, refobjsubid) AS ( + SELECT classid, objid, objsubid, + refclassid, refobjid, refobjsubid + FROM pg_depend + WHERE refclassid = 'pg_class'::regclass AND + refobjid = 'create_property_graph_tests.gt'::regclass + UNION ALL + SELECT d.classid, d.objid, d.objsubid, + d.refclassid, d.refobjid, d.refobjsubid + FROM pg_depend d + JOIN deps dp ON d.refclassid = dp.classid AND d.refobjid = dp.objid AND d.refobjsubid = dp.objsubid + ) + SELECT pg_describe_object(classid, objid, objsubid) as obj, + pg_identify_object(classid, objid, objsubid) as ident, + pg_identify_object_as_address(classid, objid, objsubid) as addr + FROM deps +) s +ORDER BY obj COLLATE "C", ident::text COLLATE "C"; + obj | ident | addr +----------------------------------------------------------+----------------------------------------------------------------------------+---------------------------------------------------------------------------- + edge e of property graph gt | ("property graph element",,,"e of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,e}",{}) + edge e of property graph gt | ("property graph element",,,"e of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,e}",{}) + edge e of property graph gt | ("property graph element",,,"e of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of property graph gt | ("property graph label",,,"e of create_property_graph_tests.gt") | ("property graph label","{create_property_graph_tests,gt,e}",{}) + label v1 of property graph gt | ("property graph label",,,"v1 of create_property_graph_tests.gt") | ("property graph label","{create_property_graph_tests,gt,v1}",{}) + label v1 of vertex v1 of property graph gt | ("property graph element label",,,"v1 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v1}",{}) + label v1 of vertex v1 of property graph gt | ("property graph element label",,,"v1 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v1}",{}) + label v2 of property graph gt | ("property graph label",,,"v2 of create_property_graph_tests.gt") | ("property graph label","{create_property_graph_tests,gt,v2}",{}) + label v2 of vertex v2 of property graph gt | ("property graph element label",,,"v2 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v2}",{}) + label v2 of vertex v2 of property graph gt | ("property graph element label",,,"v2 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v2}",{}) + property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property a of property graph gt | ("property graph property",,,"a of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,a}",{}) + property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property b of property graph gt | ("property graph property",,,"b of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,b}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of property graph gt | ("property graph property",,,"c of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,c}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of property graph gt | ("property graph property",,,"k1 of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,k1}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of property graph gt | ("property graph property",,,"k2 of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,k2}",{}) + property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property m of property graph gt | ("property graph property",,,"m of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,m}",{}) + property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property n of property graph gt | ("property graph property",,,"n of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,n}",{}) + type gt | (type,create_property_graph_tests,gt,create_property_graph_tests.gt) | (type,{create_property_graph_tests.gt},{}) + type gt[] | (type,create_property_graph_tests,_gt,create_property_graph_tests.gt[]) | (type,{create_property_graph_tests.gt[]},{}) + vertex v1 of property graph gt | ("property graph element",,,"v1 of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,v1}",{}) + vertex v2 of property graph gt | ("property graph element",,,"v2 of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,v2}",{}) +(52 rows) + \a\t SELECT pg_get_propgraphdef('g2'::regclass); CREATE PROPERTY GRAPH create_property_graph_tests.g2 diff --git a/src/test/regress/expected/event_trigger.out b/src/test/regress/expected/event_trigger.out index 065f586310f..ed8d5df397e 100644 --- a/src/test/regress/expected/event_trigger.out +++ b/src/test/regress/expected/event_trigger.out @@ -173,6 +173,23 @@ NOTICE: test_event_trigger: ddl_command_end CREATE USER MAPPING alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; NOTICE: test_event_trigger: ddl_command_end ALTER DEFAULT PRIVILEGES +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE TABLE t2x (i int PRIMARY KEY, j text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); +NOTICE: test_event_trigger: ddl_command_end CREATE PROPERTY GRAPH +DROP PROPERTY GRAPH gx; +NOTICE: test_event_trigger: ddl_command_end DROP PROPERTY GRAPH +DROP TABLE t1x, t2x; +NOTICE: test_event_trigger: ddl_command_end DROP TABLE -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; ERROR: permission denied to change owner of event trigger "regress_event_trigger" diff --git a/src/test/regress/expected/object_address.out b/src/test/regress/expected/object_address.out index 97227d67a54..5e53f0b092e 100644 --- a/src/test/regress/expected/object_address.out +++ b/src/test/regress/expected/object_address.out @@ -67,7 +67,9 @@ DECLARE BEGIN FOR objtype IN VALUES ('toast table'), ('index column'), ('sequence column'), ('toast table column'), ('view column'), ('materialized view column'), - ('property graph element'), ('property graph label'), ('property graph property') + ('property graph element'), ('property graph element label'), + ('property graph label'), ('property graph label property'), + ('property graph property') LOOP BEGIN PERFORM pg_get_object_address(objtype, '{one}', '{}'); @@ -84,7 +86,9 @@ WARNING: error for toast table column: unsupported object type "toast table col WARNING: error for view column: unsupported object type "view column" WARNING: error for materialized view column: unsupported object type "materialized view column" WARNING: error for property graph element: unsupported object type "property graph element" +WARNING: error for property graph element label: unrecognized object type "property graph element label" WARNING: error for property graph label: unsupported object type "property graph label" +WARNING: error for property graph label property: unrecognized object type "property graph label property" WARNING: error for property graph property: unsupported object type "property graph property" -- miscellaneous other errors select * from pg_get_object_address('operator of access method', '{btree,integer_ops,1}', '{int4,bool}'); @@ -593,7 +597,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace @@ -653,6 +659,8 @@ ORDER BY objects.classid, objects.objid, objects.objsubid; ("(""parameter ACL"",,,)")|("(""parameter ACL"",,)")|NULL ("(""property graph element"",,,)")|("(""property graph element"",,)")|NULL ("(""property graph label"",,,)")|("(""property graph label"",,)")|NULL +("(""property graph element label"",,,)")|("(""property graph element label"",,)")|NULL ("(""property graph property"",,,)")|("(""property graph property"",,)")|NULL +("(""property graph label property"",,,)")|("(""property graph label property"",,)")|NULL -- restore normal output mode \a\t diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..9608dd5c4af 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -298,6 +298,29 @@ SELECT (pg_identify_object(classid, objid, objsubid)).* refobjid = 'create_property_graph_tests.g2'::regclass ORDER BY 1, 2, 3, 4; +-- test object address functions with recursive dependency walk +-- covers all property graph object types including indirect dependents +SELECT * +FROM ( + WITH RECURSIVE deps (classid, objid, objsubid, refclassid, refobjid, refobjsubid) AS ( + SELECT classid, objid, objsubid, + refclassid, refobjid, refobjsubid + FROM pg_depend + WHERE refclassid = 'pg_class'::regclass AND + refobjid = 'create_property_graph_tests.gt'::regclass + UNION ALL + SELECT d.classid, d.objid, d.objsubid, + d.refclassid, d.refobjid, d.refobjsubid + FROM pg_depend d + JOIN deps dp ON d.refclassid = dp.classid AND d.refobjid = dp.objid AND d.refobjsubid = dp.objsubid + ) + SELECT pg_describe_object(classid, objid, objsubid) as obj, + pg_identify_object(classid, objid, objsubid) as ident, + pg_identify_object_as_address(classid, objid, objsubid) as addr + FROM deps +) s +ORDER BY obj COLLATE "C", ident::text COLLATE "C"; + \a\t SELECT pg_get_propgraphdef('g2'::regclass); SELECT pg_get_propgraphdef('g3'::regclass); diff --git a/src/test/regress/sql/event_trigger.sql b/src/test/regress/sql/event_trigger.sql index 32e9bb58c5e..271f443378b 100644 --- a/src/test/regress/sql/event_trigger.sql +++ b/src/test/regress/sql/event_trigger.sql @@ -143,6 +143,19 @@ create user mapping for regress_evt_user server useless_server; alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +CREATE TABLE t2x (i int PRIMARY KEY, j text); + +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); + +DROP PROPERTY GRAPH gx; +DROP TABLE t1x, t2x; + -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; diff --git a/src/test/regress/sql/object_address.sql b/src/test/regress/sql/object_address.sql index 1bbe9457c1c..27109d421c7 100644 --- a/src/test/regress/sql/object_address.sql +++ b/src/test/regress/sql/object_address.sql @@ -67,7 +67,9 @@ DECLARE BEGIN FOR objtype IN VALUES ('toast table'), ('index column'), ('sequence column'), ('toast table column'), ('view column'), ('materialized view column'), - ('property graph element'), ('property graph label'), ('property graph property') + ('property graph element'), ('property graph element label'), + ('property graph label'), ('property graph label property'), + ('property graph property') LOOP BEGIN PERFORM pg_get_object_address(objtype, '{one}', '{}'); @@ -282,7 +284,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace -- 2.34.1 --R84XrR4Hgw0dH3Ec-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v2] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-23 09:27 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-23 09:27 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing them to hit the default case and error out with "unsupported object class". During DROP PROPERTY GRAPH, this manifests when an event trigger is active, because pg_event_trigger_ddl_commands() calls these functions. The same code paths are also reachable via pg_identify_object() and pg_identify_object_as_address(). This commit adds the missing cases. Test coverage is added in object_address.sql for these two catalog types via the zero-OID test that exercises pg_identify_object() and pg_identify_object_as_address(). A test in event_trigger.sql verifies that DROP PROPERTY GRAPH works correctly when an event trigger is active. Author: Bertrand Drouvot <[email protected]> Reviewed-by: Michael Paquier <[email protected]> Reviewed-by: Ashutosh Bapat <[email protected]> Discussion: https://postgr.es/m/aej1DkLwhyZWmtxJ@bdtpg --- src/backend/catalog/objectaddress.c | 93 ++++++++++++++++++++ src/test/regress/expected/event_trigger.out | 17 ++++ src/test/regress/expected/object_address.out | 4 + src/test/regress/sql/event_trigger.sql | 13 +++ src/test/regress/sql/object_address.sql | 2 + 5 files changed, 129 insertions(+) 62.4% src/backend/catalog/ 25.6% src/test/regress/expected/ 11.8% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/event_trigger.out b/src/test/regress/expected/event_trigger.out index 065f586310f..ed8d5df397e 100644 --- a/src/test/regress/expected/event_trigger.out +++ b/src/test/regress/expected/event_trigger.out @@ -173,6 +173,23 @@ NOTICE: test_event_trigger: ddl_command_end CREATE USER MAPPING alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; NOTICE: test_event_trigger: ddl_command_end ALTER DEFAULT PRIVILEGES +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE TABLE t2x (i int PRIMARY KEY, j text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); +NOTICE: test_event_trigger: ddl_command_end CREATE PROPERTY GRAPH +DROP PROPERTY GRAPH gx; +NOTICE: test_event_trigger: ddl_command_end DROP PROPERTY GRAPH +DROP TABLE t1x, t2x; +NOTICE: test_event_trigger: ddl_command_end DROP TABLE -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; ERROR: permission denied to change owner of event trigger "regress_event_trigger" diff --git a/src/test/regress/expected/object_address.out b/src/test/regress/expected/object_address.out index 97227d67a54..729c3537f25 100644 --- a/src/test/regress/expected/object_address.out +++ b/src/test/regress/expected/object_address.out @@ -593,7 +593,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace @@ -653,6 +655,8 @@ ORDER BY objects.classid, objects.objid, objects.objsubid; ("(""parameter ACL"",,,)")|("(""parameter ACL"",,)")|NULL ("(""property graph element"",,,)")|("(""property graph element"",,)")|NULL ("(""property graph label"",,,)")|("(""property graph label"",,)")|NULL +("(""property graph element label"",,,)")|("(""property graph element label"",,)")|NULL ("(""property graph property"",,,)")|("(""property graph property"",,)")|NULL +("(""property graph label property"",,,)")|("(""property graph label property"",,)")|NULL -- restore normal output mode \a\t diff --git a/src/test/regress/sql/event_trigger.sql b/src/test/regress/sql/event_trigger.sql index 32e9bb58c5e..271f443378b 100644 --- a/src/test/regress/sql/event_trigger.sql +++ b/src/test/regress/sql/event_trigger.sql @@ -143,6 +143,19 @@ create user mapping for regress_evt_user server useless_server; alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +CREATE TABLE t2x (i int PRIMARY KEY, j text); + +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); + +DROP PROPERTY GRAPH gx; +DROP TABLE t1x, t2x; + -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; diff --git a/src/test/regress/sql/object_address.sql b/src/test/regress/sql/object_address.sql index 1bbe9457c1c..620dacf1045 100644 --- a/src/test/regress/sql/object_address.sql +++ b/src/test/regress/sql/object_address.sql @@ -282,7 +282,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace -- 2.34.1 --gtUR827Uq8d5gVsQ-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v3] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-23 09:27 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-23 09:27 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing them to hit the default case and error out with "unsupported object class". During DROP PROPERTY GRAPH, this manifests when an event trigger is active, because pg_event_trigger_ddl_commands() calls these functions. The same code paths are also reachable via pg_identify_object() and pg_identify_object_as_address(). This commit adds the missing cases. Test coverage is added in object_address.sql for these two catalog types and in create_property_graph.sql covering all property graph object types. A test in event_trigger.sql verifies that DROP PROPERTY GRAPH works correctly when an event trigger is active. Author: Bertrand Drouvot <[email protected]> Reviewed-by: Michael Paquier <[email protected]> Reviewed-by: Ashutosh Bapat <[email protected]> Discussion: https://postgr.es/m/aej1DkLwhyZWmtxJ@bdtpg --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 78 ++++++++++++++++ src/test/regress/expected/event_trigger.out | 17 ++++ src/test/regress/expected/object_address.out | 10 +- .../regress/sql/create_property_graph.sql | 23 +++++ src/test/regress/sql/event_trigger.sql | 13 +++ src/test/regress/sql/object_address.sql | 6 +- 7 files changed, 238 insertions(+), 2 deletions(-) 14.7% src/backend/catalog/ 75.5% src/test/regress/expected/ 9.7% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..eb9e17fb727 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -752,6 +752,84 @@ SELECT (pg_identify_object(classid, objid, objsubid)).* type | create_property_graph_tests | g2 | create_property_graph_tests.g2 (21 rows) +-- test object address functions with recursive dependency walk +-- covers all property graph object types including indirect dependents +SELECT * +FROM ( + WITH RECURSIVE deps (classid, objid, objsubid, refclassid, refobjid, refobjsubid) AS ( + SELECT classid, objid, objsubid, + refclassid, refobjid, refobjsubid + FROM pg_depend + WHERE refclassid = 'pg_class'::regclass AND + refobjid = 'create_property_graph_tests.gt'::regclass + UNION ALL + SELECT d.classid, d.objid, d.objsubid, + d.refclassid, d.refobjid, d.refobjsubid + FROM pg_depend d + JOIN deps dp ON d.refclassid = dp.classid AND d.refobjid = dp.objid AND d.refobjsubid = dp.objsubid + ) + SELECT pg_describe_object(classid, objid, objsubid) as obj, + pg_identify_object(classid, objid, objsubid) as ident, + pg_identify_object_as_address(classid, objid, objsubid) as addr + FROM deps +) s +ORDER BY obj COLLATE "C", ident::text COLLATE "C"; + obj | ident | addr +----------------------------------------------------------+----------------------------------------------------------------------------+---------------------------------------------------------------------------- + edge e of property graph gt | ("property graph element",,,"e of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,e}",{}) + edge e of property graph gt | ("property graph element",,,"e of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,e}",{}) + edge e of property graph gt | ("property graph element",,,"e of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of property graph gt | ("property graph label",,,"e of create_property_graph_tests.gt") | ("property graph label","{create_property_graph_tests,gt,e}",{}) + label v1 of property graph gt | ("property graph label",,,"v1 of create_property_graph_tests.gt") | ("property graph label","{create_property_graph_tests,gt,v1}",{}) + label v1 of vertex v1 of property graph gt | ("property graph element label",,,"v1 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v1}",{}) + label v1 of vertex v1 of property graph gt | ("property graph element label",,,"v1 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v1}",{}) + label v2 of property graph gt | ("property graph label",,,"v2 of create_property_graph_tests.gt") | ("property graph label","{create_property_graph_tests,gt,v2}",{}) + label v2 of vertex v2 of property graph gt | ("property graph element label",,,"v2 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v2}",{}) + label v2 of vertex v2 of property graph gt | ("property graph element label",,,"v2 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v2}",{}) + property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property a of property graph gt | ("property graph property",,,"a of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,a}",{}) + property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property b of property graph gt | ("property graph property",,,"b of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,b}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of property graph gt | ("property graph property",,,"c of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,c}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of property graph gt | ("property graph property",,,"k1 of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,k1}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of property graph gt | ("property graph property",,,"k2 of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,k2}",{}) + property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property m of property graph gt | ("property graph property",,,"m of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,m}",{}) + property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property n of property graph gt | ("property graph property",,,"n of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,n}",{}) + type gt | (type,create_property_graph_tests,gt,create_property_graph_tests.gt) | (type,{create_property_graph_tests.gt},{}) + type gt[] | (type,create_property_graph_tests,_gt,create_property_graph_tests.gt[]) | (type,{create_property_graph_tests.gt[]},{}) + vertex v1 of property graph gt | ("property graph element",,,"v1 of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,v1}",{}) + vertex v2 of property graph gt | ("property graph element",,,"v2 of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,v2}",{}) +(52 rows) + \a\t SELECT pg_get_propgraphdef('g2'::regclass); CREATE PROPERTY GRAPH create_property_graph_tests.g2 diff --git a/src/test/regress/expected/event_trigger.out b/src/test/regress/expected/event_trigger.out index 065f586310f..ed8d5df397e 100644 --- a/src/test/regress/expected/event_trigger.out +++ b/src/test/regress/expected/event_trigger.out @@ -173,6 +173,23 @@ NOTICE: test_event_trigger: ddl_command_end CREATE USER MAPPING alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; NOTICE: test_event_trigger: ddl_command_end ALTER DEFAULT PRIVILEGES +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE TABLE t2x (i int PRIMARY KEY, j text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); +NOTICE: test_event_trigger: ddl_command_end CREATE PROPERTY GRAPH +DROP PROPERTY GRAPH gx; +NOTICE: test_event_trigger: ddl_command_end DROP PROPERTY GRAPH +DROP TABLE t1x, t2x; +NOTICE: test_event_trigger: ddl_command_end DROP TABLE -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; ERROR: permission denied to change owner of event trigger "regress_event_trigger" diff --git a/src/test/regress/expected/object_address.out b/src/test/regress/expected/object_address.out index 97227d67a54..5e53f0b092e 100644 --- a/src/test/regress/expected/object_address.out +++ b/src/test/regress/expected/object_address.out @@ -67,7 +67,9 @@ DECLARE BEGIN FOR objtype IN VALUES ('toast table'), ('index column'), ('sequence column'), ('toast table column'), ('view column'), ('materialized view column'), - ('property graph element'), ('property graph label'), ('property graph property') + ('property graph element'), ('property graph element label'), + ('property graph label'), ('property graph label property'), + ('property graph property') LOOP BEGIN PERFORM pg_get_object_address(objtype, '{one}', '{}'); @@ -84,7 +86,9 @@ WARNING: error for toast table column: unsupported object type "toast table col WARNING: error for view column: unsupported object type "view column" WARNING: error for materialized view column: unsupported object type "materialized view column" WARNING: error for property graph element: unsupported object type "property graph element" +WARNING: error for property graph element label: unrecognized object type "property graph element label" WARNING: error for property graph label: unsupported object type "property graph label" +WARNING: error for property graph label property: unrecognized object type "property graph label property" WARNING: error for property graph property: unsupported object type "property graph property" -- miscellaneous other errors select * from pg_get_object_address('operator of access method', '{btree,integer_ops,1}', '{int4,bool}'); @@ -593,7 +597,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace @@ -653,6 +659,8 @@ ORDER BY objects.classid, objects.objid, objects.objsubid; ("(""parameter ACL"",,,)")|("(""parameter ACL"",,)")|NULL ("(""property graph element"",,,)")|("(""property graph element"",,)")|NULL ("(""property graph label"",,,)")|("(""property graph label"",,)")|NULL +("(""property graph element label"",,,)")|("(""property graph element label"",,)")|NULL ("(""property graph property"",,,)")|("(""property graph property"",,)")|NULL +("(""property graph label property"",,,)")|("(""property graph label property"",,)")|NULL -- restore normal output mode \a\t diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..9608dd5c4af 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -298,6 +298,29 @@ SELECT (pg_identify_object(classid, objid, objsubid)).* refobjid = 'create_property_graph_tests.g2'::regclass ORDER BY 1, 2, 3, 4; +-- test object address functions with recursive dependency walk +-- covers all property graph object types including indirect dependents +SELECT * +FROM ( + WITH RECURSIVE deps (classid, objid, objsubid, refclassid, refobjid, refobjsubid) AS ( + SELECT classid, objid, objsubid, + refclassid, refobjid, refobjsubid + FROM pg_depend + WHERE refclassid = 'pg_class'::regclass AND + refobjid = 'create_property_graph_tests.gt'::regclass + UNION ALL + SELECT d.classid, d.objid, d.objsubid, + d.refclassid, d.refobjid, d.refobjsubid + FROM pg_depend d + JOIN deps dp ON d.refclassid = dp.classid AND d.refobjid = dp.objid AND d.refobjsubid = dp.objsubid + ) + SELECT pg_describe_object(classid, objid, objsubid) as obj, + pg_identify_object(classid, objid, objsubid) as ident, + pg_identify_object_as_address(classid, objid, objsubid) as addr + FROM deps +) s +ORDER BY obj COLLATE "C", ident::text COLLATE "C"; + \a\t SELECT pg_get_propgraphdef('g2'::regclass); SELECT pg_get_propgraphdef('g3'::regclass); diff --git a/src/test/regress/sql/event_trigger.sql b/src/test/regress/sql/event_trigger.sql index 32e9bb58c5e..271f443378b 100644 --- a/src/test/regress/sql/event_trigger.sql +++ b/src/test/regress/sql/event_trigger.sql @@ -143,6 +143,19 @@ create user mapping for regress_evt_user server useless_server; alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +CREATE TABLE t2x (i int PRIMARY KEY, j text); + +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); + +DROP PROPERTY GRAPH gx; +DROP TABLE t1x, t2x; + -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; diff --git a/src/test/regress/sql/object_address.sql b/src/test/regress/sql/object_address.sql index 1bbe9457c1c..27109d421c7 100644 --- a/src/test/regress/sql/object_address.sql +++ b/src/test/regress/sql/object_address.sql @@ -67,7 +67,9 @@ DECLARE BEGIN FOR objtype IN VALUES ('toast table'), ('index column'), ('sequence column'), ('toast table column'), ('view column'), ('materialized view column'), - ('property graph element'), ('property graph label'), ('property graph property') + ('property graph element'), ('property graph element label'), + ('property graph label'), ('property graph label property'), + ('property graph property') LOOP BEGIN PERFORM pg_get_object_address(objtype, '{one}', '{}'); @@ -282,7 +284,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace -- 2.34.1 --R84XrR4Hgw0dH3Ec-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v3] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-23 09:27 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-23 09:27 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing them to hit the default case and error out with "unsupported object class". During DROP PROPERTY GRAPH, this manifests when an event trigger is active, because pg_event_trigger_ddl_commands() calls these functions. The same code paths are also reachable via pg_identify_object() and pg_identify_object_as_address(). This commit adds the missing cases. Test coverage is added in object_address.sql for these two catalog types and in create_property_graph.sql covering all property graph object types. A test in event_trigger.sql verifies that DROP PROPERTY GRAPH works correctly when an event trigger is active. Author: Bertrand Drouvot <[email protected]> Reviewed-by: Michael Paquier <[email protected]> Reviewed-by: Ashutosh Bapat <[email protected]> Discussion: https://postgr.es/m/aej1DkLwhyZWmtxJ@bdtpg --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 78 ++++++++++++++++ src/test/regress/expected/event_trigger.out | 17 ++++ src/test/regress/expected/object_address.out | 10 +- .../regress/sql/create_property_graph.sql | 23 +++++ src/test/regress/sql/event_trigger.sql | 13 +++ src/test/regress/sql/object_address.sql | 6 +- 7 files changed, 238 insertions(+), 2 deletions(-) 14.7% src/backend/catalog/ 75.5% src/test/regress/expected/ 9.7% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..eb9e17fb727 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -752,6 +752,84 @@ SELECT (pg_identify_object(classid, objid, objsubid)).* type | create_property_graph_tests | g2 | create_property_graph_tests.g2 (21 rows) +-- test object address functions with recursive dependency walk +-- covers all property graph object types including indirect dependents +SELECT * +FROM ( + WITH RECURSIVE deps (classid, objid, objsubid, refclassid, refobjid, refobjsubid) AS ( + SELECT classid, objid, objsubid, + refclassid, refobjid, refobjsubid + FROM pg_depend + WHERE refclassid = 'pg_class'::regclass AND + refobjid = 'create_property_graph_tests.gt'::regclass + UNION ALL + SELECT d.classid, d.objid, d.objsubid, + d.refclassid, d.refobjid, d.refobjsubid + FROM pg_depend d + JOIN deps dp ON d.refclassid = dp.classid AND d.refobjid = dp.objid AND d.refobjsubid = dp.objsubid + ) + SELECT pg_describe_object(classid, objid, objsubid) as obj, + pg_identify_object(classid, objid, objsubid) as ident, + pg_identify_object_as_address(classid, objid, objsubid) as addr + FROM deps +) s +ORDER BY obj COLLATE "C", ident::text COLLATE "C"; + obj | ident | addr +----------------------------------------------------------+----------------------------------------------------------------------------+---------------------------------------------------------------------------- + edge e of property graph gt | ("property graph element",,,"e of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,e}",{}) + edge e of property graph gt | ("property graph element",,,"e of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,e}",{}) + edge e of property graph gt | ("property graph element",,,"e of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of property graph gt | ("property graph label",,,"e of create_property_graph_tests.gt") | ("property graph label","{create_property_graph_tests,gt,e}",{}) + label v1 of property graph gt | ("property graph label",,,"v1 of create_property_graph_tests.gt") | ("property graph label","{create_property_graph_tests,gt,v1}",{}) + label v1 of vertex v1 of property graph gt | ("property graph element label",,,"v1 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v1}",{}) + label v1 of vertex v1 of property graph gt | ("property graph element label",,,"v1 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v1}",{}) + label v2 of property graph gt | ("property graph label",,,"v2 of create_property_graph_tests.gt") | ("property graph label","{create_property_graph_tests,gt,v2}",{}) + label v2 of vertex v2 of property graph gt | ("property graph element label",,,"v2 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v2}",{}) + label v2 of vertex v2 of property graph gt | ("property graph element label",,,"v2 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v2}",{}) + property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property a of property graph gt | ("property graph property",,,"a of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,a}",{}) + property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property b of property graph gt | ("property graph property",,,"b of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,b}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of property graph gt | ("property graph property",,,"c of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,c}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of property graph gt | ("property graph property",,,"k1 of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,k1}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of property graph gt | ("property graph property",,,"k2 of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,k2}",{}) + property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property m of property graph gt | ("property graph property",,,"m of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,m}",{}) + property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property n of property graph gt | ("property graph property",,,"n of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,n}",{}) + type gt | (type,create_property_graph_tests,gt,create_property_graph_tests.gt) | (type,{create_property_graph_tests.gt},{}) + type gt[] | (type,create_property_graph_tests,_gt,create_property_graph_tests.gt[]) | (type,{create_property_graph_tests.gt[]},{}) + vertex v1 of property graph gt | ("property graph element",,,"v1 of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,v1}",{}) + vertex v2 of property graph gt | ("property graph element",,,"v2 of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,v2}",{}) +(52 rows) + \a\t SELECT pg_get_propgraphdef('g2'::regclass); CREATE PROPERTY GRAPH create_property_graph_tests.g2 diff --git a/src/test/regress/expected/event_trigger.out b/src/test/regress/expected/event_trigger.out index 065f586310f..ed8d5df397e 100644 --- a/src/test/regress/expected/event_trigger.out +++ b/src/test/regress/expected/event_trigger.out @@ -173,6 +173,23 @@ NOTICE: test_event_trigger: ddl_command_end CREATE USER MAPPING alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; NOTICE: test_event_trigger: ddl_command_end ALTER DEFAULT PRIVILEGES +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE TABLE t2x (i int PRIMARY KEY, j text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); +NOTICE: test_event_trigger: ddl_command_end CREATE PROPERTY GRAPH +DROP PROPERTY GRAPH gx; +NOTICE: test_event_trigger: ddl_command_end DROP PROPERTY GRAPH +DROP TABLE t1x, t2x; +NOTICE: test_event_trigger: ddl_command_end DROP TABLE -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; ERROR: permission denied to change owner of event trigger "regress_event_trigger" diff --git a/src/test/regress/expected/object_address.out b/src/test/regress/expected/object_address.out index 97227d67a54..5e53f0b092e 100644 --- a/src/test/regress/expected/object_address.out +++ b/src/test/regress/expected/object_address.out @@ -67,7 +67,9 @@ DECLARE BEGIN FOR objtype IN VALUES ('toast table'), ('index column'), ('sequence column'), ('toast table column'), ('view column'), ('materialized view column'), - ('property graph element'), ('property graph label'), ('property graph property') + ('property graph element'), ('property graph element label'), + ('property graph label'), ('property graph label property'), + ('property graph property') LOOP BEGIN PERFORM pg_get_object_address(objtype, '{one}', '{}'); @@ -84,7 +86,9 @@ WARNING: error for toast table column: unsupported object type "toast table col WARNING: error for view column: unsupported object type "view column" WARNING: error for materialized view column: unsupported object type "materialized view column" WARNING: error for property graph element: unsupported object type "property graph element" +WARNING: error for property graph element label: unrecognized object type "property graph element label" WARNING: error for property graph label: unsupported object type "property graph label" +WARNING: error for property graph label property: unrecognized object type "property graph label property" WARNING: error for property graph property: unsupported object type "property graph property" -- miscellaneous other errors select * from pg_get_object_address('operator of access method', '{btree,integer_ops,1}', '{int4,bool}'); @@ -593,7 +597,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace @@ -653,6 +659,8 @@ ORDER BY objects.classid, objects.objid, objects.objsubid; ("(""parameter ACL"",,,)")|("(""parameter ACL"",,)")|NULL ("(""property graph element"",,,)")|("(""property graph element"",,)")|NULL ("(""property graph label"",,,)")|("(""property graph label"",,)")|NULL +("(""property graph element label"",,,)")|("(""property graph element label"",,)")|NULL ("(""property graph property"",,,)")|("(""property graph property"",,)")|NULL +("(""property graph label property"",,,)")|("(""property graph label property"",,)")|NULL -- restore normal output mode \a\t diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..9608dd5c4af 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -298,6 +298,29 @@ SELECT (pg_identify_object(classid, objid, objsubid)).* refobjid = 'create_property_graph_tests.g2'::regclass ORDER BY 1, 2, 3, 4; +-- test object address functions with recursive dependency walk +-- covers all property graph object types including indirect dependents +SELECT * +FROM ( + WITH RECURSIVE deps (classid, objid, objsubid, refclassid, refobjid, refobjsubid) AS ( + SELECT classid, objid, objsubid, + refclassid, refobjid, refobjsubid + FROM pg_depend + WHERE refclassid = 'pg_class'::regclass AND + refobjid = 'create_property_graph_tests.gt'::regclass + UNION ALL + SELECT d.classid, d.objid, d.objsubid, + d.refclassid, d.refobjid, d.refobjsubid + FROM pg_depend d + JOIN deps dp ON d.refclassid = dp.classid AND d.refobjid = dp.objid AND d.refobjsubid = dp.objsubid + ) + SELECT pg_describe_object(classid, objid, objsubid) as obj, + pg_identify_object(classid, objid, objsubid) as ident, + pg_identify_object_as_address(classid, objid, objsubid) as addr + FROM deps +) s +ORDER BY obj COLLATE "C", ident::text COLLATE "C"; + \a\t SELECT pg_get_propgraphdef('g2'::regclass); SELECT pg_get_propgraphdef('g3'::regclass); diff --git a/src/test/regress/sql/event_trigger.sql b/src/test/regress/sql/event_trigger.sql index 32e9bb58c5e..271f443378b 100644 --- a/src/test/regress/sql/event_trigger.sql +++ b/src/test/regress/sql/event_trigger.sql @@ -143,6 +143,19 @@ create user mapping for regress_evt_user server useless_server; alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +CREATE TABLE t2x (i int PRIMARY KEY, j text); + +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); + +DROP PROPERTY GRAPH gx; +DROP TABLE t1x, t2x; + -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; diff --git a/src/test/regress/sql/object_address.sql b/src/test/regress/sql/object_address.sql index 1bbe9457c1c..27109d421c7 100644 --- a/src/test/regress/sql/object_address.sql +++ b/src/test/regress/sql/object_address.sql @@ -67,7 +67,9 @@ DECLARE BEGIN FOR objtype IN VALUES ('toast table'), ('index column'), ('sequence column'), ('toast table column'), ('view column'), ('materialized view column'), - ('property graph element'), ('property graph label'), ('property graph property') + ('property graph element'), ('property graph element label'), + ('property graph label'), ('property graph label property'), + ('property graph property') LOOP BEGIN PERFORM pg_get_object_address(objtype, '{one}', '{}'); @@ -282,7 +284,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace -- 2.34.1 --R84XrR4Hgw0dH3Ec-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v2] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-23 09:27 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-23 09:27 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing them to hit the default case and error out with "unsupported object class". During DROP PROPERTY GRAPH, this manifests when an event trigger is active, because pg_event_trigger_ddl_commands() calls these functions. The same code paths are also reachable via pg_identify_object() and pg_identify_object_as_address(). This commit adds the missing cases. Test coverage is added in object_address.sql for these two catalog types via the zero-OID test that exercises pg_identify_object() and pg_identify_object_as_address(). A test in event_trigger.sql verifies that DROP PROPERTY GRAPH works correctly when an event trigger is active. Author: Bertrand Drouvot <[email protected]> Reviewed-by: Michael Paquier <[email protected]> Reviewed-by: Ashutosh Bapat <[email protected]> Discussion: https://postgr.es/m/aej1DkLwhyZWmtxJ@bdtpg --- src/backend/catalog/objectaddress.c | 93 ++++++++++++++++++++ src/test/regress/expected/event_trigger.out | 17 ++++ src/test/regress/expected/object_address.out | 4 + src/test/regress/sql/event_trigger.sql | 13 +++ src/test/regress/sql/object_address.sql | 2 + 5 files changed, 129 insertions(+) 62.4% src/backend/catalog/ 25.6% src/test/regress/expected/ 11.8% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/event_trigger.out b/src/test/regress/expected/event_trigger.out index 065f586310f..ed8d5df397e 100644 --- a/src/test/regress/expected/event_trigger.out +++ b/src/test/regress/expected/event_trigger.out @@ -173,6 +173,23 @@ NOTICE: test_event_trigger: ddl_command_end CREATE USER MAPPING alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; NOTICE: test_event_trigger: ddl_command_end ALTER DEFAULT PRIVILEGES +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE TABLE t2x (i int PRIMARY KEY, j text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); +NOTICE: test_event_trigger: ddl_command_end CREATE PROPERTY GRAPH +DROP PROPERTY GRAPH gx; +NOTICE: test_event_trigger: ddl_command_end DROP PROPERTY GRAPH +DROP TABLE t1x, t2x; +NOTICE: test_event_trigger: ddl_command_end DROP TABLE -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; ERROR: permission denied to change owner of event trigger "regress_event_trigger" diff --git a/src/test/regress/expected/object_address.out b/src/test/regress/expected/object_address.out index 97227d67a54..729c3537f25 100644 --- a/src/test/regress/expected/object_address.out +++ b/src/test/regress/expected/object_address.out @@ -593,7 +593,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace @@ -653,6 +655,8 @@ ORDER BY objects.classid, objects.objid, objects.objsubid; ("(""parameter ACL"",,,)")|("(""parameter ACL"",,)")|NULL ("(""property graph element"",,,)")|("(""property graph element"",,)")|NULL ("(""property graph label"",,,)")|("(""property graph label"",,)")|NULL +("(""property graph element label"",,,)")|("(""property graph element label"",,)")|NULL ("(""property graph property"",,,)")|("(""property graph property"",,)")|NULL +("(""property graph label property"",,,)")|("(""property graph label property"",,)")|NULL -- restore normal output mode \a\t diff --git a/src/test/regress/sql/event_trigger.sql b/src/test/regress/sql/event_trigger.sql index 32e9bb58c5e..271f443378b 100644 --- a/src/test/regress/sql/event_trigger.sql +++ b/src/test/regress/sql/event_trigger.sql @@ -143,6 +143,19 @@ create user mapping for regress_evt_user server useless_server; alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +CREATE TABLE t2x (i int PRIMARY KEY, j text); + +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); + +DROP PROPERTY GRAPH gx; +DROP TABLE t1x, t2x; + -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; diff --git a/src/test/regress/sql/object_address.sql b/src/test/regress/sql/object_address.sql index 1bbe9457c1c..620dacf1045 100644 --- a/src/test/regress/sql/object_address.sql +++ b/src/test/regress/sql/object_address.sql @@ -282,7 +282,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace -- 2.34.1 --gtUR827Uq8d5gVsQ-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v2] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-23 09:27 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-23 09:27 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing them to hit the default case and error out with "unsupported object class". During DROP PROPERTY GRAPH, this manifests when an event trigger is active, because pg_event_trigger_ddl_commands() calls these functions. The same code paths are also reachable via pg_identify_object() and pg_identify_object_as_address(). This commit adds the missing cases. Test coverage is added in object_address.sql for these two catalog types via the zero-OID test that exercises pg_identify_object() and pg_identify_object_as_address(). A test in event_trigger.sql verifies that DROP PROPERTY GRAPH works correctly when an event trigger is active. Author: Bertrand Drouvot <[email protected]> Reviewed-by: Michael Paquier <[email protected]> Reviewed-by: Ashutosh Bapat <[email protected]> Discussion: https://postgr.es/m/aej1DkLwhyZWmtxJ@bdtpg --- src/backend/catalog/objectaddress.c | 93 ++++++++++++++++++++ src/test/regress/expected/event_trigger.out | 17 ++++ src/test/regress/expected/object_address.out | 4 + src/test/regress/sql/event_trigger.sql | 13 +++ src/test/regress/sql/object_address.sql | 2 + 5 files changed, 129 insertions(+) 62.4% src/backend/catalog/ 25.6% src/test/regress/expected/ 11.8% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/event_trigger.out b/src/test/regress/expected/event_trigger.out index 065f586310f..ed8d5df397e 100644 --- a/src/test/regress/expected/event_trigger.out +++ b/src/test/regress/expected/event_trigger.out @@ -173,6 +173,23 @@ NOTICE: test_event_trigger: ddl_command_end CREATE USER MAPPING alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; NOTICE: test_event_trigger: ddl_command_end ALTER DEFAULT PRIVILEGES +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE TABLE t2x (i int PRIMARY KEY, j text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); +NOTICE: test_event_trigger: ddl_command_end CREATE PROPERTY GRAPH +DROP PROPERTY GRAPH gx; +NOTICE: test_event_trigger: ddl_command_end DROP PROPERTY GRAPH +DROP TABLE t1x, t2x; +NOTICE: test_event_trigger: ddl_command_end DROP TABLE -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; ERROR: permission denied to change owner of event trigger "regress_event_trigger" diff --git a/src/test/regress/expected/object_address.out b/src/test/regress/expected/object_address.out index 97227d67a54..729c3537f25 100644 --- a/src/test/regress/expected/object_address.out +++ b/src/test/regress/expected/object_address.out @@ -593,7 +593,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace @@ -653,6 +655,8 @@ ORDER BY objects.classid, objects.objid, objects.objsubid; ("(""parameter ACL"",,,)")|("(""parameter ACL"",,)")|NULL ("(""property graph element"",,,)")|("(""property graph element"",,)")|NULL ("(""property graph label"",,,)")|("(""property graph label"",,)")|NULL +("(""property graph element label"",,,)")|("(""property graph element label"",,)")|NULL ("(""property graph property"",,,)")|("(""property graph property"",,)")|NULL +("(""property graph label property"",,,)")|("(""property graph label property"",,)")|NULL -- restore normal output mode \a\t diff --git a/src/test/regress/sql/event_trigger.sql b/src/test/regress/sql/event_trigger.sql index 32e9bb58c5e..271f443378b 100644 --- a/src/test/regress/sql/event_trigger.sql +++ b/src/test/regress/sql/event_trigger.sql @@ -143,6 +143,19 @@ create user mapping for regress_evt_user server useless_server; alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +CREATE TABLE t2x (i int PRIMARY KEY, j text); + +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); + +DROP PROPERTY GRAPH gx; +DROP TABLE t1x, t2x; + -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; diff --git a/src/test/regress/sql/object_address.sql b/src/test/regress/sql/object_address.sql index 1bbe9457c1c..620dacf1045 100644 --- a/src/test/regress/sql/object_address.sql +++ b/src/test/regress/sql/object_address.sql @@ -282,7 +282,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace -- 2.34.1 --gtUR827Uq8d5gVsQ-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v2] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-23 09:27 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-23 09:27 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing them to hit the default case and error out with "unsupported object class". During DROP PROPERTY GRAPH, this manifests when an event trigger is active, because pg_event_trigger_ddl_commands() calls these functions. The same code paths are also reachable via pg_identify_object() and pg_identify_object_as_address(). This commit adds the missing cases. Test coverage is added in object_address.sql for these two catalog types via the zero-OID test that exercises pg_identify_object() and pg_identify_object_as_address(). A test in event_trigger.sql verifies that DROP PROPERTY GRAPH works correctly when an event trigger is active. Author: Bertrand Drouvot <[email protected]> Reviewed-by: Michael Paquier <[email protected]> Reviewed-by: Ashutosh Bapat <[email protected]> Discussion: https://postgr.es/m/aej1DkLwhyZWmtxJ@bdtpg --- src/backend/catalog/objectaddress.c | 93 ++++++++++++++++++++ src/test/regress/expected/event_trigger.out | 17 ++++ src/test/regress/expected/object_address.out | 4 + src/test/regress/sql/event_trigger.sql | 13 +++ src/test/regress/sql/object_address.sql | 2 + 5 files changed, 129 insertions(+) 62.4% src/backend/catalog/ 25.6% src/test/regress/expected/ 11.8% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/event_trigger.out b/src/test/regress/expected/event_trigger.out index 065f586310f..ed8d5df397e 100644 --- a/src/test/regress/expected/event_trigger.out +++ b/src/test/regress/expected/event_trigger.out @@ -173,6 +173,23 @@ NOTICE: test_event_trigger: ddl_command_end CREATE USER MAPPING alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; NOTICE: test_event_trigger: ddl_command_end ALTER DEFAULT PRIVILEGES +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE TABLE t2x (i int PRIMARY KEY, j text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); +NOTICE: test_event_trigger: ddl_command_end CREATE PROPERTY GRAPH +DROP PROPERTY GRAPH gx; +NOTICE: test_event_trigger: ddl_command_end DROP PROPERTY GRAPH +DROP TABLE t1x, t2x; +NOTICE: test_event_trigger: ddl_command_end DROP TABLE -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; ERROR: permission denied to change owner of event trigger "regress_event_trigger" diff --git a/src/test/regress/expected/object_address.out b/src/test/regress/expected/object_address.out index 97227d67a54..729c3537f25 100644 --- a/src/test/regress/expected/object_address.out +++ b/src/test/regress/expected/object_address.out @@ -593,7 +593,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace @@ -653,6 +655,8 @@ ORDER BY objects.classid, objects.objid, objects.objsubid; ("(""parameter ACL"",,,)")|("(""parameter ACL"",,)")|NULL ("(""property graph element"",,,)")|("(""property graph element"",,)")|NULL ("(""property graph label"",,,)")|("(""property graph label"",,)")|NULL +("(""property graph element label"",,,)")|("(""property graph element label"",,)")|NULL ("(""property graph property"",,,)")|("(""property graph property"",,)")|NULL +("(""property graph label property"",,,)")|("(""property graph label property"",,)")|NULL -- restore normal output mode \a\t diff --git a/src/test/regress/sql/event_trigger.sql b/src/test/regress/sql/event_trigger.sql index 32e9bb58c5e..271f443378b 100644 --- a/src/test/regress/sql/event_trigger.sql +++ b/src/test/regress/sql/event_trigger.sql @@ -143,6 +143,19 @@ create user mapping for regress_evt_user server useless_server; alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +CREATE TABLE t2x (i int PRIMARY KEY, j text); + +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); + +DROP PROPERTY GRAPH gx; +DROP TABLE t1x, t2x; + -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; diff --git a/src/test/regress/sql/object_address.sql b/src/test/regress/sql/object_address.sql index 1bbe9457c1c..620dacf1045 100644 --- a/src/test/regress/sql/object_address.sql +++ b/src/test/regress/sql/object_address.sql @@ -282,7 +282,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace -- 2.34.1 --gtUR827Uq8d5gVsQ-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v3] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-23 09:27 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-23 09:27 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing them to hit the default case and error out with "unsupported object class". During DROP PROPERTY GRAPH, this manifests when an event trigger is active, because pg_event_trigger_ddl_commands() calls these functions. The same code paths are also reachable via pg_identify_object() and pg_identify_object_as_address(). This commit adds the missing cases. Test coverage is added in object_address.sql for these two catalog types and in create_property_graph.sql covering all property graph object types. A test in event_trigger.sql verifies that DROP PROPERTY GRAPH works correctly when an event trigger is active. Author: Bertrand Drouvot <[email protected]> Reviewed-by: Michael Paquier <[email protected]> Reviewed-by: Ashutosh Bapat <[email protected]> Discussion: https://postgr.es/m/aej1DkLwhyZWmtxJ@bdtpg --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 78 ++++++++++++++++ src/test/regress/expected/event_trigger.out | 17 ++++ src/test/regress/expected/object_address.out | 10 +- .../regress/sql/create_property_graph.sql | 23 +++++ src/test/regress/sql/event_trigger.sql | 13 +++ src/test/regress/sql/object_address.sql | 6 +- 7 files changed, 238 insertions(+), 2 deletions(-) 14.7% src/backend/catalog/ 75.5% src/test/regress/expected/ 9.7% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..eb9e17fb727 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -752,6 +752,84 @@ SELECT (pg_identify_object(classid, objid, objsubid)).* type | create_property_graph_tests | g2 | create_property_graph_tests.g2 (21 rows) +-- test object address functions with recursive dependency walk +-- covers all property graph object types including indirect dependents +SELECT * +FROM ( + WITH RECURSIVE deps (classid, objid, objsubid, refclassid, refobjid, refobjsubid) AS ( + SELECT classid, objid, objsubid, + refclassid, refobjid, refobjsubid + FROM pg_depend + WHERE refclassid = 'pg_class'::regclass AND + refobjid = 'create_property_graph_tests.gt'::regclass + UNION ALL + SELECT d.classid, d.objid, d.objsubid, + d.refclassid, d.refobjid, d.refobjsubid + FROM pg_depend d + JOIN deps dp ON d.refclassid = dp.classid AND d.refobjid = dp.objid AND d.refobjsubid = dp.objsubid + ) + SELECT pg_describe_object(classid, objid, objsubid) as obj, + pg_identify_object(classid, objid, objsubid) as ident, + pg_identify_object_as_address(classid, objid, objsubid) as addr + FROM deps +) s +ORDER BY obj COLLATE "C", ident::text COLLATE "C"; + obj | ident | addr +----------------------------------------------------------+----------------------------------------------------------------------------+---------------------------------------------------------------------------- + edge e of property graph gt | ("property graph element",,,"e of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,e}",{}) + edge e of property graph gt | ("property graph element",,,"e of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,e}",{}) + edge e of property graph gt | ("property graph element",,,"e of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of property graph gt | ("property graph label",,,"e of create_property_graph_tests.gt") | ("property graph label","{create_property_graph_tests,gt,e}",{}) + label v1 of property graph gt | ("property graph label",,,"v1 of create_property_graph_tests.gt") | ("property graph label","{create_property_graph_tests,gt,v1}",{}) + label v1 of vertex v1 of property graph gt | ("property graph element label",,,"v1 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v1}",{}) + label v1 of vertex v1 of property graph gt | ("property graph element label",,,"v1 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v1}",{}) + label v2 of property graph gt | ("property graph label",,,"v2 of create_property_graph_tests.gt") | ("property graph label","{create_property_graph_tests,gt,v2}",{}) + label v2 of vertex v2 of property graph gt | ("property graph element label",,,"v2 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v2}",{}) + label v2 of vertex v2 of property graph gt | ("property graph element label",,,"v2 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v2}",{}) + property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property a of property graph gt | ("property graph property",,,"a of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,a}",{}) + property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property b of property graph gt | ("property graph property",,,"b of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,b}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of property graph gt | ("property graph property",,,"c of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,c}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of property graph gt | ("property graph property",,,"k1 of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,k1}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of property graph gt | ("property graph property",,,"k2 of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,k2}",{}) + property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property m of property graph gt | ("property graph property",,,"m of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,m}",{}) + property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property n of property graph gt | ("property graph property",,,"n of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,n}",{}) + type gt | (type,create_property_graph_tests,gt,create_property_graph_tests.gt) | (type,{create_property_graph_tests.gt},{}) + type gt[] | (type,create_property_graph_tests,_gt,create_property_graph_tests.gt[]) | (type,{create_property_graph_tests.gt[]},{}) + vertex v1 of property graph gt | ("property graph element",,,"v1 of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,v1}",{}) + vertex v2 of property graph gt | ("property graph element",,,"v2 of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,v2}",{}) +(52 rows) + \a\t SELECT pg_get_propgraphdef('g2'::regclass); CREATE PROPERTY GRAPH create_property_graph_tests.g2 diff --git a/src/test/regress/expected/event_trigger.out b/src/test/regress/expected/event_trigger.out index 065f586310f..ed8d5df397e 100644 --- a/src/test/regress/expected/event_trigger.out +++ b/src/test/regress/expected/event_trigger.out @@ -173,6 +173,23 @@ NOTICE: test_event_trigger: ddl_command_end CREATE USER MAPPING alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; NOTICE: test_event_trigger: ddl_command_end ALTER DEFAULT PRIVILEGES +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE TABLE t2x (i int PRIMARY KEY, j text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); +NOTICE: test_event_trigger: ddl_command_end CREATE PROPERTY GRAPH +DROP PROPERTY GRAPH gx; +NOTICE: test_event_trigger: ddl_command_end DROP PROPERTY GRAPH +DROP TABLE t1x, t2x; +NOTICE: test_event_trigger: ddl_command_end DROP TABLE -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; ERROR: permission denied to change owner of event trigger "regress_event_trigger" diff --git a/src/test/regress/expected/object_address.out b/src/test/regress/expected/object_address.out index 97227d67a54..5e53f0b092e 100644 --- a/src/test/regress/expected/object_address.out +++ b/src/test/regress/expected/object_address.out @@ -67,7 +67,9 @@ DECLARE BEGIN FOR objtype IN VALUES ('toast table'), ('index column'), ('sequence column'), ('toast table column'), ('view column'), ('materialized view column'), - ('property graph element'), ('property graph label'), ('property graph property') + ('property graph element'), ('property graph element label'), + ('property graph label'), ('property graph label property'), + ('property graph property') LOOP BEGIN PERFORM pg_get_object_address(objtype, '{one}', '{}'); @@ -84,7 +86,9 @@ WARNING: error for toast table column: unsupported object type "toast table col WARNING: error for view column: unsupported object type "view column" WARNING: error for materialized view column: unsupported object type "materialized view column" WARNING: error for property graph element: unsupported object type "property graph element" +WARNING: error for property graph element label: unrecognized object type "property graph element label" WARNING: error for property graph label: unsupported object type "property graph label" +WARNING: error for property graph label property: unrecognized object type "property graph label property" WARNING: error for property graph property: unsupported object type "property graph property" -- miscellaneous other errors select * from pg_get_object_address('operator of access method', '{btree,integer_ops,1}', '{int4,bool}'); @@ -593,7 +597,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace @@ -653,6 +659,8 @@ ORDER BY objects.classid, objects.objid, objects.objsubid; ("(""parameter ACL"",,,)")|("(""parameter ACL"",,)")|NULL ("(""property graph element"",,,)")|("(""property graph element"",,)")|NULL ("(""property graph label"",,,)")|("(""property graph label"",,)")|NULL +("(""property graph element label"",,,)")|("(""property graph element label"",,)")|NULL ("(""property graph property"",,,)")|("(""property graph property"",,)")|NULL +("(""property graph label property"",,,)")|("(""property graph label property"",,)")|NULL -- restore normal output mode \a\t diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..9608dd5c4af 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -298,6 +298,29 @@ SELECT (pg_identify_object(classid, objid, objsubid)).* refobjid = 'create_property_graph_tests.g2'::regclass ORDER BY 1, 2, 3, 4; +-- test object address functions with recursive dependency walk +-- covers all property graph object types including indirect dependents +SELECT * +FROM ( + WITH RECURSIVE deps (classid, objid, objsubid, refclassid, refobjid, refobjsubid) AS ( + SELECT classid, objid, objsubid, + refclassid, refobjid, refobjsubid + FROM pg_depend + WHERE refclassid = 'pg_class'::regclass AND + refobjid = 'create_property_graph_tests.gt'::regclass + UNION ALL + SELECT d.classid, d.objid, d.objsubid, + d.refclassid, d.refobjid, d.refobjsubid + FROM pg_depend d + JOIN deps dp ON d.refclassid = dp.classid AND d.refobjid = dp.objid AND d.refobjsubid = dp.objsubid + ) + SELECT pg_describe_object(classid, objid, objsubid) as obj, + pg_identify_object(classid, objid, objsubid) as ident, + pg_identify_object_as_address(classid, objid, objsubid) as addr + FROM deps +) s +ORDER BY obj COLLATE "C", ident::text COLLATE "C"; + \a\t SELECT pg_get_propgraphdef('g2'::regclass); SELECT pg_get_propgraphdef('g3'::regclass); diff --git a/src/test/regress/sql/event_trigger.sql b/src/test/regress/sql/event_trigger.sql index 32e9bb58c5e..271f443378b 100644 --- a/src/test/regress/sql/event_trigger.sql +++ b/src/test/regress/sql/event_trigger.sql @@ -143,6 +143,19 @@ create user mapping for regress_evt_user server useless_server; alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +CREATE TABLE t2x (i int PRIMARY KEY, j text); + +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); + +DROP PROPERTY GRAPH gx; +DROP TABLE t1x, t2x; + -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; diff --git a/src/test/regress/sql/object_address.sql b/src/test/regress/sql/object_address.sql index 1bbe9457c1c..27109d421c7 100644 --- a/src/test/regress/sql/object_address.sql +++ b/src/test/regress/sql/object_address.sql @@ -67,7 +67,9 @@ DECLARE BEGIN FOR objtype IN VALUES ('toast table'), ('index column'), ('sequence column'), ('toast table column'), ('view column'), ('materialized view column'), - ('property graph element'), ('property graph label'), ('property graph property') + ('property graph element'), ('property graph element label'), + ('property graph label'), ('property graph label property'), + ('property graph property') LOOP BEGIN PERFORM pg_get_object_address(objtype, '{one}', '{}'); @@ -282,7 +284,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace -- 2.34.1 --R84XrR4Hgw0dH3Ec-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v2] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-23 09:27 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-23 09:27 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing them to hit the default case and error out with "unsupported object class". During DROP PROPERTY GRAPH, this manifests when an event trigger is active, because pg_event_trigger_ddl_commands() calls these functions. The same code paths are also reachable via pg_identify_object() and pg_identify_object_as_address(). This commit adds the missing cases. Test coverage is added in object_address.sql for these two catalog types via the zero-OID test that exercises pg_identify_object() and pg_identify_object_as_address(). A test in event_trigger.sql verifies that DROP PROPERTY GRAPH works correctly when an event trigger is active. Author: Bertrand Drouvot <[email protected]> Reviewed-by: Michael Paquier <[email protected]> Reviewed-by: Ashutosh Bapat <[email protected]> Discussion: https://postgr.es/m/aej1DkLwhyZWmtxJ@bdtpg --- src/backend/catalog/objectaddress.c | 93 ++++++++++++++++++++ src/test/regress/expected/event_trigger.out | 17 ++++ src/test/regress/expected/object_address.out | 4 + src/test/regress/sql/event_trigger.sql | 13 +++ src/test/regress/sql/object_address.sql | 2 + 5 files changed, 129 insertions(+) 62.4% src/backend/catalog/ 25.6% src/test/regress/expected/ 11.8% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/event_trigger.out b/src/test/regress/expected/event_trigger.out index 065f586310f..ed8d5df397e 100644 --- a/src/test/regress/expected/event_trigger.out +++ b/src/test/regress/expected/event_trigger.out @@ -173,6 +173,23 @@ NOTICE: test_event_trigger: ddl_command_end CREATE USER MAPPING alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; NOTICE: test_event_trigger: ddl_command_end ALTER DEFAULT PRIVILEGES +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE TABLE t2x (i int PRIMARY KEY, j text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); +NOTICE: test_event_trigger: ddl_command_end CREATE PROPERTY GRAPH +DROP PROPERTY GRAPH gx; +NOTICE: test_event_trigger: ddl_command_end DROP PROPERTY GRAPH +DROP TABLE t1x, t2x; +NOTICE: test_event_trigger: ddl_command_end DROP TABLE -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; ERROR: permission denied to change owner of event trigger "regress_event_trigger" diff --git a/src/test/regress/expected/object_address.out b/src/test/regress/expected/object_address.out index 97227d67a54..729c3537f25 100644 --- a/src/test/regress/expected/object_address.out +++ b/src/test/regress/expected/object_address.out @@ -593,7 +593,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace @@ -653,6 +655,8 @@ ORDER BY objects.classid, objects.objid, objects.objsubid; ("(""parameter ACL"",,,)")|("(""parameter ACL"",,)")|NULL ("(""property graph element"",,,)")|("(""property graph element"",,)")|NULL ("(""property graph label"",,,)")|("(""property graph label"",,)")|NULL +("(""property graph element label"",,,)")|("(""property graph element label"",,)")|NULL ("(""property graph property"",,,)")|("(""property graph property"",,)")|NULL +("(""property graph label property"",,,)")|("(""property graph label property"",,)")|NULL -- restore normal output mode \a\t diff --git a/src/test/regress/sql/event_trigger.sql b/src/test/regress/sql/event_trigger.sql index 32e9bb58c5e..271f443378b 100644 --- a/src/test/regress/sql/event_trigger.sql +++ b/src/test/regress/sql/event_trigger.sql @@ -143,6 +143,19 @@ create user mapping for regress_evt_user server useless_server; alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +CREATE TABLE t2x (i int PRIMARY KEY, j text); + +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); + +DROP PROPERTY GRAPH gx; +DROP TABLE t1x, t2x; + -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; diff --git a/src/test/regress/sql/object_address.sql b/src/test/regress/sql/object_address.sql index 1bbe9457c1c..620dacf1045 100644 --- a/src/test/regress/sql/object_address.sql +++ b/src/test/regress/sql/object_address.sql @@ -282,7 +282,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace -- 2.34.1 --gtUR827Uq8d5gVsQ-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v3] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-23 09:27 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-23 09:27 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing them to hit the default case and error out with "unsupported object class". During DROP PROPERTY GRAPH, this manifests when an event trigger is active, because pg_event_trigger_ddl_commands() calls these functions. The same code paths are also reachable via pg_identify_object() and pg_identify_object_as_address(). This commit adds the missing cases. Test coverage is added in object_address.sql for these two catalog types and in create_property_graph.sql covering all property graph object types. A test in event_trigger.sql verifies that DROP PROPERTY GRAPH works correctly when an event trigger is active. Author: Bertrand Drouvot <[email protected]> Reviewed-by: Michael Paquier <[email protected]> Reviewed-by: Ashutosh Bapat <[email protected]> Discussion: https://postgr.es/m/aej1DkLwhyZWmtxJ@bdtpg --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 78 ++++++++++++++++ src/test/regress/expected/event_trigger.out | 17 ++++ src/test/regress/expected/object_address.out | 10 +- .../regress/sql/create_property_graph.sql | 23 +++++ src/test/regress/sql/event_trigger.sql | 13 +++ src/test/regress/sql/object_address.sql | 6 +- 7 files changed, 238 insertions(+), 2 deletions(-) 14.7% src/backend/catalog/ 75.5% src/test/regress/expected/ 9.7% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..eb9e17fb727 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -752,6 +752,84 @@ SELECT (pg_identify_object(classid, objid, objsubid)).* type | create_property_graph_tests | g2 | create_property_graph_tests.g2 (21 rows) +-- test object address functions with recursive dependency walk +-- covers all property graph object types including indirect dependents +SELECT * +FROM ( + WITH RECURSIVE deps (classid, objid, objsubid, refclassid, refobjid, refobjsubid) AS ( + SELECT classid, objid, objsubid, + refclassid, refobjid, refobjsubid + FROM pg_depend + WHERE refclassid = 'pg_class'::regclass AND + refobjid = 'create_property_graph_tests.gt'::regclass + UNION ALL + SELECT d.classid, d.objid, d.objsubid, + d.refclassid, d.refobjid, d.refobjsubid + FROM pg_depend d + JOIN deps dp ON d.refclassid = dp.classid AND d.refobjid = dp.objid AND d.refobjsubid = dp.objsubid + ) + SELECT pg_describe_object(classid, objid, objsubid) as obj, + pg_identify_object(classid, objid, objsubid) as ident, + pg_identify_object_as_address(classid, objid, objsubid) as addr + FROM deps +) s +ORDER BY obj COLLATE "C", ident::text COLLATE "C"; + obj | ident | addr +----------------------------------------------------------+----------------------------------------------------------------------------+---------------------------------------------------------------------------- + edge e of property graph gt | ("property graph element",,,"e of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,e}",{}) + edge e of property graph gt | ("property graph element",,,"e of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,e}",{}) + edge e of property graph gt | ("property graph element",,,"e of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of property graph gt | ("property graph label",,,"e of create_property_graph_tests.gt") | ("property graph label","{create_property_graph_tests,gt,e}",{}) + label v1 of property graph gt | ("property graph label",,,"v1 of create_property_graph_tests.gt") | ("property graph label","{create_property_graph_tests,gt,v1}",{}) + label v1 of vertex v1 of property graph gt | ("property graph element label",,,"v1 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v1}",{}) + label v1 of vertex v1 of property graph gt | ("property graph element label",,,"v1 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v1}",{}) + label v2 of property graph gt | ("property graph label",,,"v2 of create_property_graph_tests.gt") | ("property graph label","{create_property_graph_tests,gt,v2}",{}) + label v2 of vertex v2 of property graph gt | ("property graph element label",,,"v2 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v2}",{}) + label v2 of vertex v2 of property graph gt | ("property graph element label",,,"v2 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v2}",{}) + property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property a of property graph gt | ("property graph property",,,"a of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,a}",{}) + property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property b of property graph gt | ("property graph property",,,"b of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,b}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of property graph gt | ("property graph property",,,"c of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,c}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of property graph gt | ("property graph property",,,"k1 of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,k1}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of property graph gt | ("property graph property",,,"k2 of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,k2}",{}) + property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property m of property graph gt | ("property graph property",,,"m of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,m}",{}) + property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property n of property graph gt | ("property graph property",,,"n of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,n}",{}) + type gt | (type,create_property_graph_tests,gt,create_property_graph_tests.gt) | (type,{create_property_graph_tests.gt},{}) + type gt[] | (type,create_property_graph_tests,_gt,create_property_graph_tests.gt[]) | (type,{create_property_graph_tests.gt[]},{}) + vertex v1 of property graph gt | ("property graph element",,,"v1 of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,v1}",{}) + vertex v2 of property graph gt | ("property graph element",,,"v2 of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,v2}",{}) +(52 rows) + \a\t SELECT pg_get_propgraphdef('g2'::regclass); CREATE PROPERTY GRAPH create_property_graph_tests.g2 diff --git a/src/test/regress/expected/event_trigger.out b/src/test/regress/expected/event_trigger.out index 065f586310f..ed8d5df397e 100644 --- a/src/test/regress/expected/event_trigger.out +++ b/src/test/regress/expected/event_trigger.out @@ -173,6 +173,23 @@ NOTICE: test_event_trigger: ddl_command_end CREATE USER MAPPING alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; NOTICE: test_event_trigger: ddl_command_end ALTER DEFAULT PRIVILEGES +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE TABLE t2x (i int PRIMARY KEY, j text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); +NOTICE: test_event_trigger: ddl_command_end CREATE PROPERTY GRAPH +DROP PROPERTY GRAPH gx; +NOTICE: test_event_trigger: ddl_command_end DROP PROPERTY GRAPH +DROP TABLE t1x, t2x; +NOTICE: test_event_trigger: ddl_command_end DROP TABLE -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; ERROR: permission denied to change owner of event trigger "regress_event_trigger" diff --git a/src/test/regress/expected/object_address.out b/src/test/regress/expected/object_address.out index 97227d67a54..5e53f0b092e 100644 --- a/src/test/regress/expected/object_address.out +++ b/src/test/regress/expected/object_address.out @@ -67,7 +67,9 @@ DECLARE BEGIN FOR objtype IN VALUES ('toast table'), ('index column'), ('sequence column'), ('toast table column'), ('view column'), ('materialized view column'), - ('property graph element'), ('property graph label'), ('property graph property') + ('property graph element'), ('property graph element label'), + ('property graph label'), ('property graph label property'), + ('property graph property') LOOP BEGIN PERFORM pg_get_object_address(objtype, '{one}', '{}'); @@ -84,7 +86,9 @@ WARNING: error for toast table column: unsupported object type "toast table col WARNING: error for view column: unsupported object type "view column" WARNING: error for materialized view column: unsupported object type "materialized view column" WARNING: error for property graph element: unsupported object type "property graph element" +WARNING: error for property graph element label: unrecognized object type "property graph element label" WARNING: error for property graph label: unsupported object type "property graph label" +WARNING: error for property graph label property: unrecognized object type "property graph label property" WARNING: error for property graph property: unsupported object type "property graph property" -- miscellaneous other errors select * from pg_get_object_address('operator of access method', '{btree,integer_ops,1}', '{int4,bool}'); @@ -593,7 +597,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace @@ -653,6 +659,8 @@ ORDER BY objects.classid, objects.objid, objects.objsubid; ("(""parameter ACL"",,,)")|("(""parameter ACL"",,)")|NULL ("(""property graph element"",,,)")|("(""property graph element"",,)")|NULL ("(""property graph label"",,,)")|("(""property graph label"",,)")|NULL +("(""property graph element label"",,,)")|("(""property graph element label"",,)")|NULL ("(""property graph property"",,,)")|("(""property graph property"",,)")|NULL +("(""property graph label property"",,,)")|("(""property graph label property"",,)")|NULL -- restore normal output mode \a\t diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..9608dd5c4af 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -298,6 +298,29 @@ SELECT (pg_identify_object(classid, objid, objsubid)).* refobjid = 'create_property_graph_tests.g2'::regclass ORDER BY 1, 2, 3, 4; +-- test object address functions with recursive dependency walk +-- covers all property graph object types including indirect dependents +SELECT * +FROM ( + WITH RECURSIVE deps (classid, objid, objsubid, refclassid, refobjid, refobjsubid) AS ( + SELECT classid, objid, objsubid, + refclassid, refobjid, refobjsubid + FROM pg_depend + WHERE refclassid = 'pg_class'::regclass AND + refobjid = 'create_property_graph_tests.gt'::regclass + UNION ALL + SELECT d.classid, d.objid, d.objsubid, + d.refclassid, d.refobjid, d.refobjsubid + FROM pg_depend d + JOIN deps dp ON d.refclassid = dp.classid AND d.refobjid = dp.objid AND d.refobjsubid = dp.objsubid + ) + SELECT pg_describe_object(classid, objid, objsubid) as obj, + pg_identify_object(classid, objid, objsubid) as ident, + pg_identify_object_as_address(classid, objid, objsubid) as addr + FROM deps +) s +ORDER BY obj COLLATE "C", ident::text COLLATE "C"; + \a\t SELECT pg_get_propgraphdef('g2'::regclass); SELECT pg_get_propgraphdef('g3'::regclass); diff --git a/src/test/regress/sql/event_trigger.sql b/src/test/regress/sql/event_trigger.sql index 32e9bb58c5e..271f443378b 100644 --- a/src/test/regress/sql/event_trigger.sql +++ b/src/test/regress/sql/event_trigger.sql @@ -143,6 +143,19 @@ create user mapping for regress_evt_user server useless_server; alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +CREATE TABLE t2x (i int PRIMARY KEY, j text); + +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); + +DROP PROPERTY GRAPH gx; +DROP TABLE t1x, t2x; + -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; diff --git a/src/test/regress/sql/object_address.sql b/src/test/regress/sql/object_address.sql index 1bbe9457c1c..27109d421c7 100644 --- a/src/test/regress/sql/object_address.sql +++ b/src/test/regress/sql/object_address.sql @@ -67,7 +67,9 @@ DECLARE BEGIN FOR objtype IN VALUES ('toast table'), ('index column'), ('sequence column'), ('toast table column'), ('view column'), ('materialized view column'), - ('property graph element'), ('property graph label'), ('property graph property') + ('property graph element'), ('property graph element label'), + ('property graph label'), ('property graph label property'), + ('property graph property') LOOP BEGIN PERFORM pg_get_object_address(objtype, '{one}', '{}'); @@ -282,7 +284,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace -- 2.34.1 --R84XrR4Hgw0dH3Ec-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v3] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-23 09:27 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-23 09:27 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing them to hit the default case and error out with "unsupported object class". During DROP PROPERTY GRAPH, this manifests when an event trigger is active, because pg_event_trigger_ddl_commands() calls these functions. The same code paths are also reachable via pg_identify_object() and pg_identify_object_as_address(). This commit adds the missing cases. Test coverage is added in object_address.sql for these two catalog types and in create_property_graph.sql covering all property graph object types. A test in event_trigger.sql verifies that DROP PROPERTY GRAPH works correctly when an event trigger is active. Author: Bertrand Drouvot <[email protected]> Reviewed-by: Michael Paquier <[email protected]> Reviewed-by: Ashutosh Bapat <[email protected]> Discussion: https://postgr.es/m/aej1DkLwhyZWmtxJ@bdtpg --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 78 ++++++++++++++++ src/test/regress/expected/event_trigger.out | 17 ++++ src/test/regress/expected/object_address.out | 10 +- .../regress/sql/create_property_graph.sql | 23 +++++ src/test/regress/sql/event_trigger.sql | 13 +++ src/test/regress/sql/object_address.sql | 6 +- 7 files changed, 238 insertions(+), 2 deletions(-) 14.7% src/backend/catalog/ 75.5% src/test/regress/expected/ 9.7% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..eb9e17fb727 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -752,6 +752,84 @@ SELECT (pg_identify_object(classid, objid, objsubid)).* type | create_property_graph_tests | g2 | create_property_graph_tests.g2 (21 rows) +-- test object address functions with recursive dependency walk +-- covers all property graph object types including indirect dependents +SELECT * +FROM ( + WITH RECURSIVE deps (classid, objid, objsubid, refclassid, refobjid, refobjsubid) AS ( + SELECT classid, objid, objsubid, + refclassid, refobjid, refobjsubid + FROM pg_depend + WHERE refclassid = 'pg_class'::regclass AND + refobjid = 'create_property_graph_tests.gt'::regclass + UNION ALL + SELECT d.classid, d.objid, d.objsubid, + d.refclassid, d.refobjid, d.refobjsubid + FROM pg_depend d + JOIN deps dp ON d.refclassid = dp.classid AND d.refobjid = dp.objid AND d.refobjsubid = dp.objsubid + ) + SELECT pg_describe_object(classid, objid, objsubid) as obj, + pg_identify_object(classid, objid, objsubid) as ident, + pg_identify_object_as_address(classid, objid, objsubid) as addr + FROM deps +) s +ORDER BY obj COLLATE "C", ident::text COLLATE "C"; + obj | ident | addr +----------------------------------------------------------+----------------------------------------------------------------------------+---------------------------------------------------------------------------- + edge e of property graph gt | ("property graph element",,,"e of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,e}",{}) + edge e of property graph gt | ("property graph element",,,"e of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,e}",{}) + edge e of property graph gt | ("property graph element",,,"e of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of property graph gt | ("property graph label",,,"e of create_property_graph_tests.gt") | ("property graph label","{create_property_graph_tests,gt,e}",{}) + label v1 of property graph gt | ("property graph label",,,"v1 of create_property_graph_tests.gt") | ("property graph label","{create_property_graph_tests,gt,v1}",{}) + label v1 of vertex v1 of property graph gt | ("property graph element label",,,"v1 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v1}",{}) + label v1 of vertex v1 of property graph gt | ("property graph element label",,,"v1 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v1}",{}) + label v2 of property graph gt | ("property graph label",,,"v2 of create_property_graph_tests.gt") | ("property graph label","{create_property_graph_tests,gt,v2}",{}) + label v2 of vertex v2 of property graph gt | ("property graph element label",,,"v2 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v2}",{}) + label v2 of vertex v2 of property graph gt | ("property graph element label",,,"v2 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v2}",{}) + property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property a of property graph gt | ("property graph property",,,"a of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,a}",{}) + property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property b of property graph gt | ("property graph property",,,"b of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,b}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of property graph gt | ("property graph property",,,"c of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,c}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of property graph gt | ("property graph property",,,"k1 of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,k1}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of property graph gt | ("property graph property",,,"k2 of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,k2}",{}) + property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property m of property graph gt | ("property graph property",,,"m of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,m}",{}) + property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property n of property graph gt | ("property graph property",,,"n of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,n}",{}) + type gt | (type,create_property_graph_tests,gt,create_property_graph_tests.gt) | (type,{create_property_graph_tests.gt},{}) + type gt[] | (type,create_property_graph_tests,_gt,create_property_graph_tests.gt[]) | (type,{create_property_graph_tests.gt[]},{}) + vertex v1 of property graph gt | ("property graph element",,,"v1 of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,v1}",{}) + vertex v2 of property graph gt | ("property graph element",,,"v2 of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,v2}",{}) +(52 rows) + \a\t SELECT pg_get_propgraphdef('g2'::regclass); CREATE PROPERTY GRAPH create_property_graph_tests.g2 diff --git a/src/test/regress/expected/event_trigger.out b/src/test/regress/expected/event_trigger.out index 065f586310f..ed8d5df397e 100644 --- a/src/test/regress/expected/event_trigger.out +++ b/src/test/regress/expected/event_trigger.out @@ -173,6 +173,23 @@ NOTICE: test_event_trigger: ddl_command_end CREATE USER MAPPING alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; NOTICE: test_event_trigger: ddl_command_end ALTER DEFAULT PRIVILEGES +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE TABLE t2x (i int PRIMARY KEY, j text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); +NOTICE: test_event_trigger: ddl_command_end CREATE PROPERTY GRAPH +DROP PROPERTY GRAPH gx; +NOTICE: test_event_trigger: ddl_command_end DROP PROPERTY GRAPH +DROP TABLE t1x, t2x; +NOTICE: test_event_trigger: ddl_command_end DROP TABLE -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; ERROR: permission denied to change owner of event trigger "regress_event_trigger" diff --git a/src/test/regress/expected/object_address.out b/src/test/regress/expected/object_address.out index 97227d67a54..5e53f0b092e 100644 --- a/src/test/regress/expected/object_address.out +++ b/src/test/regress/expected/object_address.out @@ -67,7 +67,9 @@ DECLARE BEGIN FOR objtype IN VALUES ('toast table'), ('index column'), ('sequence column'), ('toast table column'), ('view column'), ('materialized view column'), - ('property graph element'), ('property graph label'), ('property graph property') + ('property graph element'), ('property graph element label'), + ('property graph label'), ('property graph label property'), + ('property graph property') LOOP BEGIN PERFORM pg_get_object_address(objtype, '{one}', '{}'); @@ -84,7 +86,9 @@ WARNING: error for toast table column: unsupported object type "toast table col WARNING: error for view column: unsupported object type "view column" WARNING: error for materialized view column: unsupported object type "materialized view column" WARNING: error for property graph element: unsupported object type "property graph element" +WARNING: error for property graph element label: unrecognized object type "property graph element label" WARNING: error for property graph label: unsupported object type "property graph label" +WARNING: error for property graph label property: unrecognized object type "property graph label property" WARNING: error for property graph property: unsupported object type "property graph property" -- miscellaneous other errors select * from pg_get_object_address('operator of access method', '{btree,integer_ops,1}', '{int4,bool}'); @@ -593,7 +597,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace @@ -653,6 +659,8 @@ ORDER BY objects.classid, objects.objid, objects.objsubid; ("(""parameter ACL"",,,)")|("(""parameter ACL"",,)")|NULL ("(""property graph element"",,,)")|("(""property graph element"",,)")|NULL ("(""property graph label"",,,)")|("(""property graph label"",,)")|NULL +("(""property graph element label"",,,)")|("(""property graph element label"",,)")|NULL ("(""property graph property"",,,)")|("(""property graph property"",,)")|NULL +("(""property graph label property"",,,)")|("(""property graph label property"",,)")|NULL -- restore normal output mode \a\t diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..9608dd5c4af 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -298,6 +298,29 @@ SELECT (pg_identify_object(classid, objid, objsubid)).* refobjid = 'create_property_graph_tests.g2'::regclass ORDER BY 1, 2, 3, 4; +-- test object address functions with recursive dependency walk +-- covers all property graph object types including indirect dependents +SELECT * +FROM ( + WITH RECURSIVE deps (classid, objid, objsubid, refclassid, refobjid, refobjsubid) AS ( + SELECT classid, objid, objsubid, + refclassid, refobjid, refobjsubid + FROM pg_depend + WHERE refclassid = 'pg_class'::regclass AND + refobjid = 'create_property_graph_tests.gt'::regclass + UNION ALL + SELECT d.classid, d.objid, d.objsubid, + d.refclassid, d.refobjid, d.refobjsubid + FROM pg_depend d + JOIN deps dp ON d.refclassid = dp.classid AND d.refobjid = dp.objid AND d.refobjsubid = dp.objsubid + ) + SELECT pg_describe_object(classid, objid, objsubid) as obj, + pg_identify_object(classid, objid, objsubid) as ident, + pg_identify_object_as_address(classid, objid, objsubid) as addr + FROM deps +) s +ORDER BY obj COLLATE "C", ident::text COLLATE "C"; + \a\t SELECT pg_get_propgraphdef('g2'::regclass); SELECT pg_get_propgraphdef('g3'::regclass); diff --git a/src/test/regress/sql/event_trigger.sql b/src/test/regress/sql/event_trigger.sql index 32e9bb58c5e..271f443378b 100644 --- a/src/test/regress/sql/event_trigger.sql +++ b/src/test/regress/sql/event_trigger.sql @@ -143,6 +143,19 @@ create user mapping for regress_evt_user server useless_server; alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +CREATE TABLE t2x (i int PRIMARY KEY, j text); + +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); + +DROP PROPERTY GRAPH gx; +DROP TABLE t1x, t2x; + -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; diff --git a/src/test/regress/sql/object_address.sql b/src/test/regress/sql/object_address.sql index 1bbe9457c1c..27109d421c7 100644 --- a/src/test/regress/sql/object_address.sql +++ b/src/test/regress/sql/object_address.sql @@ -67,7 +67,9 @@ DECLARE BEGIN FOR objtype IN VALUES ('toast table'), ('index column'), ('sequence column'), ('toast table column'), ('view column'), ('materialized view column'), - ('property graph element'), ('property graph label'), ('property graph property') + ('property graph element'), ('property graph element label'), + ('property graph label'), ('property graph label property'), + ('property graph property') LOOP BEGIN PERFORM pg_get_object_address(objtype, '{one}', '{}'); @@ -282,7 +284,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace -- 2.34.1 --R84XrR4Hgw0dH3Ec-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v2] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-23 09:27 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-23 09:27 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing them to hit the default case and error out with "unsupported object class". During DROP PROPERTY GRAPH, this manifests when an event trigger is active, because pg_event_trigger_ddl_commands() calls these functions. The same code paths are also reachable via pg_identify_object() and pg_identify_object_as_address(). This commit adds the missing cases. Test coverage is added in object_address.sql for these two catalog types via the zero-OID test that exercises pg_identify_object() and pg_identify_object_as_address(). A test in event_trigger.sql verifies that DROP PROPERTY GRAPH works correctly when an event trigger is active. Author: Bertrand Drouvot <[email protected]> Reviewed-by: Michael Paquier <[email protected]> Reviewed-by: Ashutosh Bapat <[email protected]> Discussion: https://postgr.es/m/aej1DkLwhyZWmtxJ@bdtpg --- src/backend/catalog/objectaddress.c | 93 ++++++++++++++++++++ src/test/regress/expected/event_trigger.out | 17 ++++ src/test/regress/expected/object_address.out | 4 + src/test/regress/sql/event_trigger.sql | 13 +++ src/test/regress/sql/object_address.sql | 2 + 5 files changed, 129 insertions(+) 62.4% src/backend/catalog/ 25.6% src/test/regress/expected/ 11.8% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/event_trigger.out b/src/test/regress/expected/event_trigger.out index 065f586310f..ed8d5df397e 100644 --- a/src/test/regress/expected/event_trigger.out +++ b/src/test/regress/expected/event_trigger.out @@ -173,6 +173,23 @@ NOTICE: test_event_trigger: ddl_command_end CREATE USER MAPPING alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; NOTICE: test_event_trigger: ddl_command_end ALTER DEFAULT PRIVILEGES +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE TABLE t2x (i int PRIMARY KEY, j text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); +NOTICE: test_event_trigger: ddl_command_end CREATE PROPERTY GRAPH +DROP PROPERTY GRAPH gx; +NOTICE: test_event_trigger: ddl_command_end DROP PROPERTY GRAPH +DROP TABLE t1x, t2x; +NOTICE: test_event_trigger: ddl_command_end DROP TABLE -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; ERROR: permission denied to change owner of event trigger "regress_event_trigger" diff --git a/src/test/regress/expected/object_address.out b/src/test/regress/expected/object_address.out index 97227d67a54..729c3537f25 100644 --- a/src/test/regress/expected/object_address.out +++ b/src/test/regress/expected/object_address.out @@ -593,7 +593,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace @@ -653,6 +655,8 @@ ORDER BY objects.classid, objects.objid, objects.objsubid; ("(""parameter ACL"",,,)")|("(""parameter ACL"",,)")|NULL ("(""property graph element"",,,)")|("(""property graph element"",,)")|NULL ("(""property graph label"",,,)")|("(""property graph label"",,)")|NULL +("(""property graph element label"",,,)")|("(""property graph element label"",,)")|NULL ("(""property graph property"",,,)")|("(""property graph property"",,)")|NULL +("(""property graph label property"",,,)")|("(""property graph label property"",,)")|NULL -- restore normal output mode \a\t diff --git a/src/test/regress/sql/event_trigger.sql b/src/test/regress/sql/event_trigger.sql index 32e9bb58c5e..271f443378b 100644 --- a/src/test/regress/sql/event_trigger.sql +++ b/src/test/regress/sql/event_trigger.sql @@ -143,6 +143,19 @@ create user mapping for regress_evt_user server useless_server; alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +CREATE TABLE t2x (i int PRIMARY KEY, j text); + +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); + +DROP PROPERTY GRAPH gx; +DROP TABLE t1x, t2x; + -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; diff --git a/src/test/regress/sql/object_address.sql b/src/test/regress/sql/object_address.sql index 1bbe9457c1c..620dacf1045 100644 --- a/src/test/regress/sql/object_address.sql +++ b/src/test/regress/sql/object_address.sql @@ -282,7 +282,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace -- 2.34.1 --gtUR827Uq8d5gVsQ-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v2] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-23 09:27 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-23 09:27 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing them to hit the default case and error out with "unsupported object class". During DROP PROPERTY GRAPH, this manifests when an event trigger is active, because pg_event_trigger_ddl_commands() calls these functions. The same code paths are also reachable via pg_identify_object() and pg_identify_object_as_address(). This commit adds the missing cases. Test coverage is added in object_address.sql for these two catalog types via the zero-OID test that exercises pg_identify_object() and pg_identify_object_as_address(). A test in event_trigger.sql verifies that DROP PROPERTY GRAPH works correctly when an event trigger is active. Author: Bertrand Drouvot <[email protected]> Reviewed-by: Michael Paquier <[email protected]> Reviewed-by: Ashutosh Bapat <[email protected]> Discussion: https://postgr.es/m/aej1DkLwhyZWmtxJ@bdtpg --- src/backend/catalog/objectaddress.c | 93 ++++++++++++++++++++ src/test/regress/expected/event_trigger.out | 17 ++++ src/test/regress/expected/object_address.out | 4 + src/test/regress/sql/event_trigger.sql | 13 +++ src/test/regress/sql/object_address.sql | 2 + 5 files changed, 129 insertions(+) 62.4% src/backend/catalog/ 25.6% src/test/regress/expected/ 11.8% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/event_trigger.out b/src/test/regress/expected/event_trigger.out index 065f586310f..ed8d5df397e 100644 --- a/src/test/regress/expected/event_trigger.out +++ b/src/test/regress/expected/event_trigger.out @@ -173,6 +173,23 @@ NOTICE: test_event_trigger: ddl_command_end CREATE USER MAPPING alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; NOTICE: test_event_trigger: ddl_command_end ALTER DEFAULT PRIVILEGES +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE TABLE t2x (i int PRIMARY KEY, j text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); +NOTICE: test_event_trigger: ddl_command_end CREATE PROPERTY GRAPH +DROP PROPERTY GRAPH gx; +NOTICE: test_event_trigger: ddl_command_end DROP PROPERTY GRAPH +DROP TABLE t1x, t2x; +NOTICE: test_event_trigger: ddl_command_end DROP TABLE -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; ERROR: permission denied to change owner of event trigger "regress_event_trigger" diff --git a/src/test/regress/expected/object_address.out b/src/test/regress/expected/object_address.out index 97227d67a54..729c3537f25 100644 --- a/src/test/regress/expected/object_address.out +++ b/src/test/regress/expected/object_address.out @@ -593,7 +593,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace @@ -653,6 +655,8 @@ ORDER BY objects.classid, objects.objid, objects.objsubid; ("(""parameter ACL"",,,)")|("(""parameter ACL"",,)")|NULL ("(""property graph element"",,,)")|("(""property graph element"",,)")|NULL ("(""property graph label"",,,)")|("(""property graph label"",,)")|NULL +("(""property graph element label"",,,)")|("(""property graph element label"",,)")|NULL ("(""property graph property"",,,)")|("(""property graph property"",,)")|NULL +("(""property graph label property"",,,)")|("(""property graph label property"",,)")|NULL -- restore normal output mode \a\t diff --git a/src/test/regress/sql/event_trigger.sql b/src/test/regress/sql/event_trigger.sql index 32e9bb58c5e..271f443378b 100644 --- a/src/test/regress/sql/event_trigger.sql +++ b/src/test/regress/sql/event_trigger.sql @@ -143,6 +143,19 @@ create user mapping for regress_evt_user server useless_server; alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +CREATE TABLE t2x (i int PRIMARY KEY, j text); + +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); + +DROP PROPERTY GRAPH gx; +DROP TABLE t1x, t2x; + -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; diff --git a/src/test/regress/sql/object_address.sql b/src/test/regress/sql/object_address.sql index 1bbe9457c1c..620dacf1045 100644 --- a/src/test/regress/sql/object_address.sql +++ b/src/test/regress/sql/object_address.sql @@ -282,7 +282,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace -- 2.34.1 --gtUR827Uq8d5gVsQ-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v3] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-23 09:27 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-23 09:27 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing them to hit the default case and error out with "unsupported object class". During DROP PROPERTY GRAPH, this manifests when an event trigger is active, because pg_event_trigger_ddl_commands() calls these functions. The same code paths are also reachable via pg_identify_object() and pg_identify_object_as_address(). This commit adds the missing cases. Test coverage is added in object_address.sql for these two catalog types and in create_property_graph.sql covering all property graph object types. A test in event_trigger.sql verifies that DROP PROPERTY GRAPH works correctly when an event trigger is active. Author: Bertrand Drouvot <[email protected]> Reviewed-by: Michael Paquier <[email protected]> Reviewed-by: Ashutosh Bapat <[email protected]> Discussion: https://postgr.es/m/aej1DkLwhyZWmtxJ@bdtpg --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 78 ++++++++++++++++ src/test/regress/expected/event_trigger.out | 17 ++++ src/test/regress/expected/object_address.out | 10 +- .../regress/sql/create_property_graph.sql | 23 +++++ src/test/regress/sql/event_trigger.sql | 13 +++ src/test/regress/sql/object_address.sql | 6 +- 7 files changed, 238 insertions(+), 2 deletions(-) 14.7% src/backend/catalog/ 75.5% src/test/regress/expected/ 9.7% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..eb9e17fb727 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -752,6 +752,84 @@ SELECT (pg_identify_object(classid, objid, objsubid)).* type | create_property_graph_tests | g2 | create_property_graph_tests.g2 (21 rows) +-- test object address functions with recursive dependency walk +-- covers all property graph object types including indirect dependents +SELECT * +FROM ( + WITH RECURSIVE deps (classid, objid, objsubid, refclassid, refobjid, refobjsubid) AS ( + SELECT classid, objid, objsubid, + refclassid, refobjid, refobjsubid + FROM pg_depend + WHERE refclassid = 'pg_class'::regclass AND + refobjid = 'create_property_graph_tests.gt'::regclass + UNION ALL + SELECT d.classid, d.objid, d.objsubid, + d.refclassid, d.refobjid, d.refobjsubid + FROM pg_depend d + JOIN deps dp ON d.refclassid = dp.classid AND d.refobjid = dp.objid AND d.refobjsubid = dp.objsubid + ) + SELECT pg_describe_object(classid, objid, objsubid) as obj, + pg_identify_object(classid, objid, objsubid) as ident, + pg_identify_object_as_address(classid, objid, objsubid) as addr + FROM deps +) s +ORDER BY obj COLLATE "C", ident::text COLLATE "C"; + obj | ident | addr +----------------------------------------------------------+----------------------------------------------------------------------------+---------------------------------------------------------------------------- + edge e of property graph gt | ("property graph element",,,"e of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,e}",{}) + edge e of property graph gt | ("property graph element",,,"e of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,e}",{}) + edge e of property graph gt | ("property graph element",,,"e of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of property graph gt | ("property graph label",,,"e of create_property_graph_tests.gt") | ("property graph label","{create_property_graph_tests,gt,e}",{}) + label v1 of property graph gt | ("property graph label",,,"v1 of create_property_graph_tests.gt") | ("property graph label","{create_property_graph_tests,gt,v1}",{}) + label v1 of vertex v1 of property graph gt | ("property graph element label",,,"v1 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v1}",{}) + label v1 of vertex v1 of property graph gt | ("property graph element label",,,"v1 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v1}",{}) + label v2 of property graph gt | ("property graph label",,,"v2 of create_property_graph_tests.gt") | ("property graph label","{create_property_graph_tests,gt,v2}",{}) + label v2 of vertex v2 of property graph gt | ("property graph element label",,,"v2 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v2}",{}) + label v2 of vertex v2 of property graph gt | ("property graph element label",,,"v2 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v2}",{}) + property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property a of property graph gt | ("property graph property",,,"a of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,a}",{}) + property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property b of property graph gt | ("property graph property",,,"b of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,b}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of property graph gt | ("property graph property",,,"c of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,c}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of property graph gt | ("property graph property",,,"k1 of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,k1}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of property graph gt | ("property graph property",,,"k2 of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,k2}",{}) + property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property m of property graph gt | ("property graph property",,,"m of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,m}",{}) + property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property n of property graph gt | ("property graph property",,,"n of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,n}",{}) + type gt | (type,create_property_graph_tests,gt,create_property_graph_tests.gt) | (type,{create_property_graph_tests.gt},{}) + type gt[] | (type,create_property_graph_tests,_gt,create_property_graph_tests.gt[]) | (type,{create_property_graph_tests.gt[]},{}) + vertex v1 of property graph gt | ("property graph element",,,"v1 of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,v1}",{}) + vertex v2 of property graph gt | ("property graph element",,,"v2 of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,v2}",{}) +(52 rows) + \a\t SELECT pg_get_propgraphdef('g2'::regclass); CREATE PROPERTY GRAPH create_property_graph_tests.g2 diff --git a/src/test/regress/expected/event_trigger.out b/src/test/regress/expected/event_trigger.out index 065f586310f..ed8d5df397e 100644 --- a/src/test/regress/expected/event_trigger.out +++ b/src/test/regress/expected/event_trigger.out @@ -173,6 +173,23 @@ NOTICE: test_event_trigger: ddl_command_end CREATE USER MAPPING alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; NOTICE: test_event_trigger: ddl_command_end ALTER DEFAULT PRIVILEGES +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE TABLE t2x (i int PRIMARY KEY, j text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); +NOTICE: test_event_trigger: ddl_command_end CREATE PROPERTY GRAPH +DROP PROPERTY GRAPH gx; +NOTICE: test_event_trigger: ddl_command_end DROP PROPERTY GRAPH +DROP TABLE t1x, t2x; +NOTICE: test_event_trigger: ddl_command_end DROP TABLE -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; ERROR: permission denied to change owner of event trigger "regress_event_trigger" diff --git a/src/test/regress/expected/object_address.out b/src/test/regress/expected/object_address.out index 97227d67a54..5e53f0b092e 100644 --- a/src/test/regress/expected/object_address.out +++ b/src/test/regress/expected/object_address.out @@ -67,7 +67,9 @@ DECLARE BEGIN FOR objtype IN VALUES ('toast table'), ('index column'), ('sequence column'), ('toast table column'), ('view column'), ('materialized view column'), - ('property graph element'), ('property graph label'), ('property graph property') + ('property graph element'), ('property graph element label'), + ('property graph label'), ('property graph label property'), + ('property graph property') LOOP BEGIN PERFORM pg_get_object_address(objtype, '{one}', '{}'); @@ -84,7 +86,9 @@ WARNING: error for toast table column: unsupported object type "toast table col WARNING: error for view column: unsupported object type "view column" WARNING: error for materialized view column: unsupported object type "materialized view column" WARNING: error for property graph element: unsupported object type "property graph element" +WARNING: error for property graph element label: unrecognized object type "property graph element label" WARNING: error for property graph label: unsupported object type "property graph label" +WARNING: error for property graph label property: unrecognized object type "property graph label property" WARNING: error for property graph property: unsupported object type "property graph property" -- miscellaneous other errors select * from pg_get_object_address('operator of access method', '{btree,integer_ops,1}', '{int4,bool}'); @@ -593,7 +597,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace @@ -653,6 +659,8 @@ ORDER BY objects.classid, objects.objid, objects.objsubid; ("(""parameter ACL"",,,)")|("(""parameter ACL"",,)")|NULL ("(""property graph element"",,,)")|("(""property graph element"",,)")|NULL ("(""property graph label"",,,)")|("(""property graph label"",,)")|NULL +("(""property graph element label"",,,)")|("(""property graph element label"",,)")|NULL ("(""property graph property"",,,)")|("(""property graph property"",,)")|NULL +("(""property graph label property"",,,)")|("(""property graph label property"",,)")|NULL -- restore normal output mode \a\t diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..9608dd5c4af 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -298,6 +298,29 @@ SELECT (pg_identify_object(classid, objid, objsubid)).* refobjid = 'create_property_graph_tests.g2'::regclass ORDER BY 1, 2, 3, 4; +-- test object address functions with recursive dependency walk +-- covers all property graph object types including indirect dependents +SELECT * +FROM ( + WITH RECURSIVE deps (classid, objid, objsubid, refclassid, refobjid, refobjsubid) AS ( + SELECT classid, objid, objsubid, + refclassid, refobjid, refobjsubid + FROM pg_depend + WHERE refclassid = 'pg_class'::regclass AND + refobjid = 'create_property_graph_tests.gt'::regclass + UNION ALL + SELECT d.classid, d.objid, d.objsubid, + d.refclassid, d.refobjid, d.refobjsubid + FROM pg_depend d + JOIN deps dp ON d.refclassid = dp.classid AND d.refobjid = dp.objid AND d.refobjsubid = dp.objsubid + ) + SELECT pg_describe_object(classid, objid, objsubid) as obj, + pg_identify_object(classid, objid, objsubid) as ident, + pg_identify_object_as_address(classid, objid, objsubid) as addr + FROM deps +) s +ORDER BY obj COLLATE "C", ident::text COLLATE "C"; + \a\t SELECT pg_get_propgraphdef('g2'::regclass); SELECT pg_get_propgraphdef('g3'::regclass); diff --git a/src/test/regress/sql/event_trigger.sql b/src/test/regress/sql/event_trigger.sql index 32e9bb58c5e..271f443378b 100644 --- a/src/test/regress/sql/event_trigger.sql +++ b/src/test/regress/sql/event_trigger.sql @@ -143,6 +143,19 @@ create user mapping for regress_evt_user server useless_server; alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +CREATE TABLE t2x (i int PRIMARY KEY, j text); + +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); + +DROP PROPERTY GRAPH gx; +DROP TABLE t1x, t2x; + -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; diff --git a/src/test/regress/sql/object_address.sql b/src/test/regress/sql/object_address.sql index 1bbe9457c1c..27109d421c7 100644 --- a/src/test/regress/sql/object_address.sql +++ b/src/test/regress/sql/object_address.sql @@ -67,7 +67,9 @@ DECLARE BEGIN FOR objtype IN VALUES ('toast table'), ('index column'), ('sequence column'), ('toast table column'), ('view column'), ('materialized view column'), - ('property graph element'), ('property graph label'), ('property graph property') + ('property graph element'), ('property graph element label'), + ('property graph label'), ('property graph label property'), + ('property graph property') LOOP BEGIN PERFORM pg_get_object_address(objtype, '{one}', '{}'); @@ -282,7 +284,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace -- 2.34.1 --R84XrR4Hgw0dH3Ec-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v3] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-23 09:27 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-23 09:27 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing them to hit the default case and error out with "unsupported object class". During DROP PROPERTY GRAPH, this manifests when an event trigger is active, because pg_event_trigger_ddl_commands() calls these functions. The same code paths are also reachable via pg_identify_object() and pg_identify_object_as_address(). This commit adds the missing cases. Test coverage is added in object_address.sql for these two catalog types and in create_property_graph.sql covering all property graph object types. A test in event_trigger.sql verifies that DROP PROPERTY GRAPH works correctly when an event trigger is active. Author: Bertrand Drouvot <[email protected]> Reviewed-by: Michael Paquier <[email protected]> Reviewed-by: Ashutosh Bapat <[email protected]> Discussion: https://postgr.es/m/aej1DkLwhyZWmtxJ@bdtpg --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 78 ++++++++++++++++ src/test/regress/expected/event_trigger.out | 17 ++++ src/test/regress/expected/object_address.out | 10 +- .../regress/sql/create_property_graph.sql | 23 +++++ src/test/regress/sql/event_trigger.sql | 13 +++ src/test/regress/sql/object_address.sql | 6 +- 7 files changed, 238 insertions(+), 2 deletions(-) 14.7% src/backend/catalog/ 75.5% src/test/regress/expected/ 9.7% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..eb9e17fb727 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -752,6 +752,84 @@ SELECT (pg_identify_object(classid, objid, objsubid)).* type | create_property_graph_tests | g2 | create_property_graph_tests.g2 (21 rows) +-- test object address functions with recursive dependency walk +-- covers all property graph object types including indirect dependents +SELECT * +FROM ( + WITH RECURSIVE deps (classid, objid, objsubid, refclassid, refobjid, refobjsubid) AS ( + SELECT classid, objid, objsubid, + refclassid, refobjid, refobjsubid + FROM pg_depend + WHERE refclassid = 'pg_class'::regclass AND + refobjid = 'create_property_graph_tests.gt'::regclass + UNION ALL + SELECT d.classid, d.objid, d.objsubid, + d.refclassid, d.refobjid, d.refobjsubid + FROM pg_depend d + JOIN deps dp ON d.refclassid = dp.classid AND d.refobjid = dp.objid AND d.refobjsubid = dp.objsubid + ) + SELECT pg_describe_object(classid, objid, objsubid) as obj, + pg_identify_object(classid, objid, objsubid) as ident, + pg_identify_object_as_address(classid, objid, objsubid) as addr + FROM deps +) s +ORDER BY obj COLLATE "C", ident::text COLLATE "C"; + obj | ident | addr +----------------------------------------------------------+----------------------------------------------------------------------------+---------------------------------------------------------------------------- + edge e of property graph gt | ("property graph element",,,"e of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,e}",{}) + edge e of property graph gt | ("property graph element",,,"e of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,e}",{}) + edge e of property graph gt | ("property graph element",,,"e of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of property graph gt | ("property graph label",,,"e of create_property_graph_tests.gt") | ("property graph label","{create_property_graph_tests,gt,e}",{}) + label v1 of property graph gt | ("property graph label",,,"v1 of create_property_graph_tests.gt") | ("property graph label","{create_property_graph_tests,gt,v1}",{}) + label v1 of vertex v1 of property graph gt | ("property graph element label",,,"v1 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v1}",{}) + label v1 of vertex v1 of property graph gt | ("property graph element label",,,"v1 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v1}",{}) + label v2 of property graph gt | ("property graph label",,,"v2 of create_property_graph_tests.gt") | ("property graph label","{create_property_graph_tests,gt,v2}",{}) + label v2 of vertex v2 of property graph gt | ("property graph element label",,,"v2 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v2}",{}) + label v2 of vertex v2 of property graph gt | ("property graph element label",,,"v2 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v2}",{}) + property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property a of property graph gt | ("property graph property",,,"a of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,a}",{}) + property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property b of property graph gt | ("property graph property",,,"b of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,b}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of property graph gt | ("property graph property",,,"c of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,c}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of property graph gt | ("property graph property",,,"k1 of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,k1}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of property graph gt | ("property graph property",,,"k2 of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,k2}",{}) + property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property m of property graph gt | ("property graph property",,,"m of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,m}",{}) + property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property n of property graph gt | ("property graph property",,,"n of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,n}",{}) + type gt | (type,create_property_graph_tests,gt,create_property_graph_tests.gt) | (type,{create_property_graph_tests.gt},{}) + type gt[] | (type,create_property_graph_tests,_gt,create_property_graph_tests.gt[]) | (type,{create_property_graph_tests.gt[]},{}) + vertex v1 of property graph gt | ("property graph element",,,"v1 of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,v1}",{}) + vertex v2 of property graph gt | ("property graph element",,,"v2 of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,v2}",{}) +(52 rows) + \a\t SELECT pg_get_propgraphdef('g2'::regclass); CREATE PROPERTY GRAPH create_property_graph_tests.g2 diff --git a/src/test/regress/expected/event_trigger.out b/src/test/regress/expected/event_trigger.out index 065f586310f..ed8d5df397e 100644 --- a/src/test/regress/expected/event_trigger.out +++ b/src/test/regress/expected/event_trigger.out @@ -173,6 +173,23 @@ NOTICE: test_event_trigger: ddl_command_end CREATE USER MAPPING alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; NOTICE: test_event_trigger: ddl_command_end ALTER DEFAULT PRIVILEGES +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE TABLE t2x (i int PRIMARY KEY, j text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); +NOTICE: test_event_trigger: ddl_command_end CREATE PROPERTY GRAPH +DROP PROPERTY GRAPH gx; +NOTICE: test_event_trigger: ddl_command_end DROP PROPERTY GRAPH +DROP TABLE t1x, t2x; +NOTICE: test_event_trigger: ddl_command_end DROP TABLE -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; ERROR: permission denied to change owner of event trigger "regress_event_trigger" diff --git a/src/test/regress/expected/object_address.out b/src/test/regress/expected/object_address.out index 97227d67a54..5e53f0b092e 100644 --- a/src/test/regress/expected/object_address.out +++ b/src/test/regress/expected/object_address.out @@ -67,7 +67,9 @@ DECLARE BEGIN FOR objtype IN VALUES ('toast table'), ('index column'), ('sequence column'), ('toast table column'), ('view column'), ('materialized view column'), - ('property graph element'), ('property graph label'), ('property graph property') + ('property graph element'), ('property graph element label'), + ('property graph label'), ('property graph label property'), + ('property graph property') LOOP BEGIN PERFORM pg_get_object_address(objtype, '{one}', '{}'); @@ -84,7 +86,9 @@ WARNING: error for toast table column: unsupported object type "toast table col WARNING: error for view column: unsupported object type "view column" WARNING: error for materialized view column: unsupported object type "materialized view column" WARNING: error for property graph element: unsupported object type "property graph element" +WARNING: error for property graph element label: unrecognized object type "property graph element label" WARNING: error for property graph label: unsupported object type "property graph label" +WARNING: error for property graph label property: unrecognized object type "property graph label property" WARNING: error for property graph property: unsupported object type "property graph property" -- miscellaneous other errors select * from pg_get_object_address('operator of access method', '{btree,integer_ops,1}', '{int4,bool}'); @@ -593,7 +597,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace @@ -653,6 +659,8 @@ ORDER BY objects.classid, objects.objid, objects.objsubid; ("(""parameter ACL"",,,)")|("(""parameter ACL"",,)")|NULL ("(""property graph element"",,,)")|("(""property graph element"",,)")|NULL ("(""property graph label"",,,)")|("(""property graph label"",,)")|NULL +("(""property graph element label"",,,)")|("(""property graph element label"",,)")|NULL ("(""property graph property"",,,)")|("(""property graph property"",,)")|NULL +("(""property graph label property"",,,)")|("(""property graph label property"",,)")|NULL -- restore normal output mode \a\t diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..9608dd5c4af 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -298,6 +298,29 @@ SELECT (pg_identify_object(classid, objid, objsubid)).* refobjid = 'create_property_graph_tests.g2'::regclass ORDER BY 1, 2, 3, 4; +-- test object address functions with recursive dependency walk +-- covers all property graph object types including indirect dependents +SELECT * +FROM ( + WITH RECURSIVE deps (classid, objid, objsubid, refclassid, refobjid, refobjsubid) AS ( + SELECT classid, objid, objsubid, + refclassid, refobjid, refobjsubid + FROM pg_depend + WHERE refclassid = 'pg_class'::regclass AND + refobjid = 'create_property_graph_tests.gt'::regclass + UNION ALL + SELECT d.classid, d.objid, d.objsubid, + d.refclassid, d.refobjid, d.refobjsubid + FROM pg_depend d + JOIN deps dp ON d.refclassid = dp.classid AND d.refobjid = dp.objid AND d.refobjsubid = dp.objsubid + ) + SELECT pg_describe_object(classid, objid, objsubid) as obj, + pg_identify_object(classid, objid, objsubid) as ident, + pg_identify_object_as_address(classid, objid, objsubid) as addr + FROM deps +) s +ORDER BY obj COLLATE "C", ident::text COLLATE "C"; + \a\t SELECT pg_get_propgraphdef('g2'::regclass); SELECT pg_get_propgraphdef('g3'::regclass); diff --git a/src/test/regress/sql/event_trigger.sql b/src/test/regress/sql/event_trigger.sql index 32e9bb58c5e..271f443378b 100644 --- a/src/test/regress/sql/event_trigger.sql +++ b/src/test/regress/sql/event_trigger.sql @@ -143,6 +143,19 @@ create user mapping for regress_evt_user server useless_server; alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +CREATE TABLE t2x (i int PRIMARY KEY, j text); + +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); + +DROP PROPERTY GRAPH gx; +DROP TABLE t1x, t2x; + -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; diff --git a/src/test/regress/sql/object_address.sql b/src/test/regress/sql/object_address.sql index 1bbe9457c1c..27109d421c7 100644 --- a/src/test/regress/sql/object_address.sql +++ b/src/test/regress/sql/object_address.sql @@ -67,7 +67,9 @@ DECLARE BEGIN FOR objtype IN VALUES ('toast table'), ('index column'), ('sequence column'), ('toast table column'), ('view column'), ('materialized view column'), - ('property graph element'), ('property graph label'), ('property graph property') + ('property graph element'), ('property graph element label'), + ('property graph label'), ('property graph label property'), + ('property graph property') LOOP BEGIN PERFORM pg_get_object_address(objtype, '{one}', '{}'); @@ -282,7 +284,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace -- 2.34.1 --R84XrR4Hgw0dH3Ec-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v3] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-23 09:27 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-23 09:27 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing them to hit the default case and error out with "unsupported object class". During DROP PROPERTY GRAPH, this manifests when an event trigger is active, because pg_event_trigger_ddl_commands() calls these functions. The same code paths are also reachable via pg_identify_object() and pg_identify_object_as_address(). This commit adds the missing cases. Test coverage is added in object_address.sql for these two catalog types and in create_property_graph.sql covering all property graph object types. A test in event_trigger.sql verifies that DROP PROPERTY GRAPH works correctly when an event trigger is active. Author: Bertrand Drouvot <[email protected]> Reviewed-by: Michael Paquier <[email protected]> Reviewed-by: Ashutosh Bapat <[email protected]> Discussion: https://postgr.es/m/aej1DkLwhyZWmtxJ@bdtpg --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 78 ++++++++++++++++ src/test/regress/expected/event_trigger.out | 17 ++++ src/test/regress/expected/object_address.out | 10 +- .../regress/sql/create_property_graph.sql | 23 +++++ src/test/regress/sql/event_trigger.sql | 13 +++ src/test/regress/sql/object_address.sql | 6 +- 7 files changed, 238 insertions(+), 2 deletions(-) 14.7% src/backend/catalog/ 75.5% src/test/regress/expected/ 9.7% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..eb9e17fb727 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -752,6 +752,84 @@ SELECT (pg_identify_object(classid, objid, objsubid)).* type | create_property_graph_tests | g2 | create_property_graph_tests.g2 (21 rows) +-- test object address functions with recursive dependency walk +-- covers all property graph object types including indirect dependents +SELECT * +FROM ( + WITH RECURSIVE deps (classid, objid, objsubid, refclassid, refobjid, refobjsubid) AS ( + SELECT classid, objid, objsubid, + refclassid, refobjid, refobjsubid + FROM pg_depend + WHERE refclassid = 'pg_class'::regclass AND + refobjid = 'create_property_graph_tests.gt'::regclass + UNION ALL + SELECT d.classid, d.objid, d.objsubid, + d.refclassid, d.refobjid, d.refobjsubid + FROM pg_depend d + JOIN deps dp ON d.refclassid = dp.classid AND d.refobjid = dp.objid AND d.refobjsubid = dp.objsubid + ) + SELECT pg_describe_object(classid, objid, objsubid) as obj, + pg_identify_object(classid, objid, objsubid) as ident, + pg_identify_object_as_address(classid, objid, objsubid) as addr + FROM deps +) s +ORDER BY obj COLLATE "C", ident::text COLLATE "C"; + obj | ident | addr +----------------------------------------------------------+----------------------------------------------------------------------------+---------------------------------------------------------------------------- + edge e of property graph gt | ("property graph element",,,"e of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,e}",{}) + edge e of property graph gt | ("property graph element",,,"e of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,e}",{}) + edge e of property graph gt | ("property graph element",,,"e of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of property graph gt | ("property graph label",,,"e of create_property_graph_tests.gt") | ("property graph label","{create_property_graph_tests,gt,e}",{}) + label v1 of property graph gt | ("property graph label",,,"v1 of create_property_graph_tests.gt") | ("property graph label","{create_property_graph_tests,gt,v1}",{}) + label v1 of vertex v1 of property graph gt | ("property graph element label",,,"v1 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v1}",{}) + label v1 of vertex v1 of property graph gt | ("property graph element label",,,"v1 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v1}",{}) + label v2 of property graph gt | ("property graph label",,,"v2 of create_property_graph_tests.gt") | ("property graph label","{create_property_graph_tests,gt,v2}",{}) + label v2 of vertex v2 of property graph gt | ("property graph element label",,,"v2 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v2}",{}) + label v2 of vertex v2 of property graph gt | ("property graph element label",,,"v2 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v2}",{}) + property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property a of property graph gt | ("property graph property",,,"a of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,a}",{}) + property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property b of property graph gt | ("property graph property",,,"b of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,b}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of property graph gt | ("property graph property",,,"c of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,c}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of property graph gt | ("property graph property",,,"k1 of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,k1}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of property graph gt | ("property graph property",,,"k2 of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,k2}",{}) + property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property m of property graph gt | ("property graph property",,,"m of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,m}",{}) + property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property n of property graph gt | ("property graph property",,,"n of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,n}",{}) + type gt | (type,create_property_graph_tests,gt,create_property_graph_tests.gt) | (type,{create_property_graph_tests.gt},{}) + type gt[] | (type,create_property_graph_tests,_gt,create_property_graph_tests.gt[]) | (type,{create_property_graph_tests.gt[]},{}) + vertex v1 of property graph gt | ("property graph element",,,"v1 of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,v1}",{}) + vertex v2 of property graph gt | ("property graph element",,,"v2 of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,v2}",{}) +(52 rows) + \a\t SELECT pg_get_propgraphdef('g2'::regclass); CREATE PROPERTY GRAPH create_property_graph_tests.g2 diff --git a/src/test/regress/expected/event_trigger.out b/src/test/regress/expected/event_trigger.out index 065f586310f..ed8d5df397e 100644 --- a/src/test/regress/expected/event_trigger.out +++ b/src/test/regress/expected/event_trigger.out @@ -173,6 +173,23 @@ NOTICE: test_event_trigger: ddl_command_end CREATE USER MAPPING alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; NOTICE: test_event_trigger: ddl_command_end ALTER DEFAULT PRIVILEGES +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE TABLE t2x (i int PRIMARY KEY, j text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); +NOTICE: test_event_trigger: ddl_command_end CREATE PROPERTY GRAPH +DROP PROPERTY GRAPH gx; +NOTICE: test_event_trigger: ddl_command_end DROP PROPERTY GRAPH +DROP TABLE t1x, t2x; +NOTICE: test_event_trigger: ddl_command_end DROP TABLE -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; ERROR: permission denied to change owner of event trigger "regress_event_trigger" diff --git a/src/test/regress/expected/object_address.out b/src/test/regress/expected/object_address.out index 97227d67a54..5e53f0b092e 100644 --- a/src/test/regress/expected/object_address.out +++ b/src/test/regress/expected/object_address.out @@ -67,7 +67,9 @@ DECLARE BEGIN FOR objtype IN VALUES ('toast table'), ('index column'), ('sequence column'), ('toast table column'), ('view column'), ('materialized view column'), - ('property graph element'), ('property graph label'), ('property graph property') + ('property graph element'), ('property graph element label'), + ('property graph label'), ('property graph label property'), + ('property graph property') LOOP BEGIN PERFORM pg_get_object_address(objtype, '{one}', '{}'); @@ -84,7 +86,9 @@ WARNING: error for toast table column: unsupported object type "toast table col WARNING: error for view column: unsupported object type "view column" WARNING: error for materialized view column: unsupported object type "materialized view column" WARNING: error for property graph element: unsupported object type "property graph element" +WARNING: error for property graph element label: unrecognized object type "property graph element label" WARNING: error for property graph label: unsupported object type "property graph label" +WARNING: error for property graph label property: unrecognized object type "property graph label property" WARNING: error for property graph property: unsupported object type "property graph property" -- miscellaneous other errors select * from pg_get_object_address('operator of access method', '{btree,integer_ops,1}', '{int4,bool}'); @@ -593,7 +597,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace @@ -653,6 +659,8 @@ ORDER BY objects.classid, objects.objid, objects.objsubid; ("(""parameter ACL"",,,)")|("(""parameter ACL"",,)")|NULL ("(""property graph element"",,,)")|("(""property graph element"",,)")|NULL ("(""property graph label"",,,)")|("(""property graph label"",,)")|NULL +("(""property graph element label"",,,)")|("(""property graph element label"",,)")|NULL ("(""property graph property"",,,)")|("(""property graph property"",,)")|NULL +("(""property graph label property"",,,)")|("(""property graph label property"",,)")|NULL -- restore normal output mode \a\t diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..9608dd5c4af 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -298,6 +298,29 @@ SELECT (pg_identify_object(classid, objid, objsubid)).* refobjid = 'create_property_graph_tests.g2'::regclass ORDER BY 1, 2, 3, 4; +-- test object address functions with recursive dependency walk +-- covers all property graph object types including indirect dependents +SELECT * +FROM ( + WITH RECURSIVE deps (classid, objid, objsubid, refclassid, refobjid, refobjsubid) AS ( + SELECT classid, objid, objsubid, + refclassid, refobjid, refobjsubid + FROM pg_depend + WHERE refclassid = 'pg_class'::regclass AND + refobjid = 'create_property_graph_tests.gt'::regclass + UNION ALL + SELECT d.classid, d.objid, d.objsubid, + d.refclassid, d.refobjid, d.refobjsubid + FROM pg_depend d + JOIN deps dp ON d.refclassid = dp.classid AND d.refobjid = dp.objid AND d.refobjsubid = dp.objsubid + ) + SELECT pg_describe_object(classid, objid, objsubid) as obj, + pg_identify_object(classid, objid, objsubid) as ident, + pg_identify_object_as_address(classid, objid, objsubid) as addr + FROM deps +) s +ORDER BY obj COLLATE "C", ident::text COLLATE "C"; + \a\t SELECT pg_get_propgraphdef('g2'::regclass); SELECT pg_get_propgraphdef('g3'::regclass); diff --git a/src/test/regress/sql/event_trigger.sql b/src/test/regress/sql/event_trigger.sql index 32e9bb58c5e..271f443378b 100644 --- a/src/test/regress/sql/event_trigger.sql +++ b/src/test/regress/sql/event_trigger.sql @@ -143,6 +143,19 @@ create user mapping for regress_evt_user server useless_server; alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +CREATE TABLE t2x (i int PRIMARY KEY, j text); + +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); + +DROP PROPERTY GRAPH gx; +DROP TABLE t1x, t2x; + -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; diff --git a/src/test/regress/sql/object_address.sql b/src/test/regress/sql/object_address.sql index 1bbe9457c1c..27109d421c7 100644 --- a/src/test/regress/sql/object_address.sql +++ b/src/test/regress/sql/object_address.sql @@ -67,7 +67,9 @@ DECLARE BEGIN FOR objtype IN VALUES ('toast table'), ('index column'), ('sequence column'), ('toast table column'), ('view column'), ('materialized view column'), - ('property graph element'), ('property graph label'), ('property graph property') + ('property graph element'), ('property graph element label'), + ('property graph label'), ('property graph label property'), + ('property graph property') LOOP BEGIN PERFORM pg_get_object_address(objtype, '{one}', '{}'); @@ -282,7 +284,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace -- 2.34.1 --R84XrR4Hgw0dH3Ec-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v3] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-23 09:27 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-23 09:27 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing them to hit the default case and error out with "unsupported object class". During DROP PROPERTY GRAPH, this manifests when an event trigger is active, because pg_event_trigger_ddl_commands() calls these functions. The same code paths are also reachable via pg_identify_object() and pg_identify_object_as_address(). This commit adds the missing cases. Test coverage is added in object_address.sql for these two catalog types and in create_property_graph.sql covering all property graph object types. A test in event_trigger.sql verifies that DROP PROPERTY GRAPH works correctly when an event trigger is active. Author: Bertrand Drouvot <[email protected]> Reviewed-by: Michael Paquier <[email protected]> Reviewed-by: Ashutosh Bapat <[email protected]> Discussion: https://postgr.es/m/aej1DkLwhyZWmtxJ@bdtpg --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 78 ++++++++++++++++ src/test/regress/expected/event_trigger.out | 17 ++++ src/test/regress/expected/object_address.out | 10 +- .../regress/sql/create_property_graph.sql | 23 +++++ src/test/regress/sql/event_trigger.sql | 13 +++ src/test/regress/sql/object_address.sql | 6 +- 7 files changed, 238 insertions(+), 2 deletions(-) 14.7% src/backend/catalog/ 75.5% src/test/regress/expected/ 9.7% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..eb9e17fb727 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -752,6 +752,84 @@ SELECT (pg_identify_object(classid, objid, objsubid)).* type | create_property_graph_tests | g2 | create_property_graph_tests.g2 (21 rows) +-- test object address functions with recursive dependency walk +-- covers all property graph object types including indirect dependents +SELECT * +FROM ( + WITH RECURSIVE deps (classid, objid, objsubid, refclassid, refobjid, refobjsubid) AS ( + SELECT classid, objid, objsubid, + refclassid, refobjid, refobjsubid + FROM pg_depend + WHERE refclassid = 'pg_class'::regclass AND + refobjid = 'create_property_graph_tests.gt'::regclass + UNION ALL + SELECT d.classid, d.objid, d.objsubid, + d.refclassid, d.refobjid, d.refobjsubid + FROM pg_depend d + JOIN deps dp ON d.refclassid = dp.classid AND d.refobjid = dp.objid AND d.refobjsubid = dp.objsubid + ) + SELECT pg_describe_object(classid, objid, objsubid) as obj, + pg_identify_object(classid, objid, objsubid) as ident, + pg_identify_object_as_address(classid, objid, objsubid) as addr + FROM deps +) s +ORDER BY obj COLLATE "C", ident::text COLLATE "C"; + obj | ident | addr +----------------------------------------------------------+----------------------------------------------------------------------------+---------------------------------------------------------------------------- + edge e of property graph gt | ("property graph element",,,"e of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,e}",{}) + edge e of property graph gt | ("property graph element",,,"e of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,e}",{}) + edge e of property graph gt | ("property graph element",,,"e of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of property graph gt | ("property graph label",,,"e of create_property_graph_tests.gt") | ("property graph label","{create_property_graph_tests,gt,e}",{}) + label v1 of property graph gt | ("property graph label",,,"v1 of create_property_graph_tests.gt") | ("property graph label","{create_property_graph_tests,gt,v1}",{}) + label v1 of vertex v1 of property graph gt | ("property graph element label",,,"v1 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v1}",{}) + label v1 of vertex v1 of property graph gt | ("property graph element label",,,"v1 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v1}",{}) + label v2 of property graph gt | ("property graph label",,,"v2 of create_property_graph_tests.gt") | ("property graph label","{create_property_graph_tests,gt,v2}",{}) + label v2 of vertex v2 of property graph gt | ("property graph element label",,,"v2 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v2}",{}) + label v2 of vertex v2 of property graph gt | ("property graph element label",,,"v2 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v2}",{}) + property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property a of property graph gt | ("property graph property",,,"a of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,a}",{}) + property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property b of property graph gt | ("property graph property",,,"b of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,b}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of property graph gt | ("property graph property",,,"c of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,c}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of property graph gt | ("property graph property",,,"k1 of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,k1}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of property graph gt | ("property graph property",,,"k2 of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,k2}",{}) + property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property m of property graph gt | ("property graph property",,,"m of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,m}",{}) + property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property n of property graph gt | ("property graph property",,,"n of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,n}",{}) + type gt | (type,create_property_graph_tests,gt,create_property_graph_tests.gt) | (type,{create_property_graph_tests.gt},{}) + type gt[] | (type,create_property_graph_tests,_gt,create_property_graph_tests.gt[]) | (type,{create_property_graph_tests.gt[]},{}) + vertex v1 of property graph gt | ("property graph element",,,"v1 of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,v1}",{}) + vertex v2 of property graph gt | ("property graph element",,,"v2 of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,v2}",{}) +(52 rows) + \a\t SELECT pg_get_propgraphdef('g2'::regclass); CREATE PROPERTY GRAPH create_property_graph_tests.g2 diff --git a/src/test/regress/expected/event_trigger.out b/src/test/regress/expected/event_trigger.out index 065f586310f..ed8d5df397e 100644 --- a/src/test/regress/expected/event_trigger.out +++ b/src/test/regress/expected/event_trigger.out @@ -173,6 +173,23 @@ NOTICE: test_event_trigger: ddl_command_end CREATE USER MAPPING alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; NOTICE: test_event_trigger: ddl_command_end ALTER DEFAULT PRIVILEGES +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE TABLE t2x (i int PRIMARY KEY, j text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); +NOTICE: test_event_trigger: ddl_command_end CREATE PROPERTY GRAPH +DROP PROPERTY GRAPH gx; +NOTICE: test_event_trigger: ddl_command_end DROP PROPERTY GRAPH +DROP TABLE t1x, t2x; +NOTICE: test_event_trigger: ddl_command_end DROP TABLE -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; ERROR: permission denied to change owner of event trigger "regress_event_trigger" diff --git a/src/test/regress/expected/object_address.out b/src/test/regress/expected/object_address.out index 97227d67a54..5e53f0b092e 100644 --- a/src/test/regress/expected/object_address.out +++ b/src/test/regress/expected/object_address.out @@ -67,7 +67,9 @@ DECLARE BEGIN FOR objtype IN VALUES ('toast table'), ('index column'), ('sequence column'), ('toast table column'), ('view column'), ('materialized view column'), - ('property graph element'), ('property graph label'), ('property graph property') + ('property graph element'), ('property graph element label'), + ('property graph label'), ('property graph label property'), + ('property graph property') LOOP BEGIN PERFORM pg_get_object_address(objtype, '{one}', '{}'); @@ -84,7 +86,9 @@ WARNING: error for toast table column: unsupported object type "toast table col WARNING: error for view column: unsupported object type "view column" WARNING: error for materialized view column: unsupported object type "materialized view column" WARNING: error for property graph element: unsupported object type "property graph element" +WARNING: error for property graph element label: unrecognized object type "property graph element label" WARNING: error for property graph label: unsupported object type "property graph label" +WARNING: error for property graph label property: unrecognized object type "property graph label property" WARNING: error for property graph property: unsupported object type "property graph property" -- miscellaneous other errors select * from pg_get_object_address('operator of access method', '{btree,integer_ops,1}', '{int4,bool}'); @@ -593,7 +597,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace @@ -653,6 +659,8 @@ ORDER BY objects.classid, objects.objid, objects.objsubid; ("(""parameter ACL"",,,)")|("(""parameter ACL"",,)")|NULL ("(""property graph element"",,,)")|("(""property graph element"",,)")|NULL ("(""property graph label"",,,)")|("(""property graph label"",,)")|NULL +("(""property graph element label"",,,)")|("(""property graph element label"",,)")|NULL ("(""property graph property"",,,)")|("(""property graph property"",,)")|NULL +("(""property graph label property"",,,)")|("(""property graph label property"",,)")|NULL -- restore normal output mode \a\t diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..9608dd5c4af 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -298,6 +298,29 @@ SELECT (pg_identify_object(classid, objid, objsubid)).* refobjid = 'create_property_graph_tests.g2'::regclass ORDER BY 1, 2, 3, 4; +-- test object address functions with recursive dependency walk +-- covers all property graph object types including indirect dependents +SELECT * +FROM ( + WITH RECURSIVE deps (classid, objid, objsubid, refclassid, refobjid, refobjsubid) AS ( + SELECT classid, objid, objsubid, + refclassid, refobjid, refobjsubid + FROM pg_depend + WHERE refclassid = 'pg_class'::regclass AND + refobjid = 'create_property_graph_tests.gt'::regclass + UNION ALL + SELECT d.classid, d.objid, d.objsubid, + d.refclassid, d.refobjid, d.refobjsubid + FROM pg_depend d + JOIN deps dp ON d.refclassid = dp.classid AND d.refobjid = dp.objid AND d.refobjsubid = dp.objsubid + ) + SELECT pg_describe_object(classid, objid, objsubid) as obj, + pg_identify_object(classid, objid, objsubid) as ident, + pg_identify_object_as_address(classid, objid, objsubid) as addr + FROM deps +) s +ORDER BY obj COLLATE "C", ident::text COLLATE "C"; + \a\t SELECT pg_get_propgraphdef('g2'::regclass); SELECT pg_get_propgraphdef('g3'::regclass); diff --git a/src/test/regress/sql/event_trigger.sql b/src/test/regress/sql/event_trigger.sql index 32e9bb58c5e..271f443378b 100644 --- a/src/test/regress/sql/event_trigger.sql +++ b/src/test/regress/sql/event_trigger.sql @@ -143,6 +143,19 @@ create user mapping for regress_evt_user server useless_server; alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +CREATE TABLE t2x (i int PRIMARY KEY, j text); + +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); + +DROP PROPERTY GRAPH gx; +DROP TABLE t1x, t2x; + -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; diff --git a/src/test/regress/sql/object_address.sql b/src/test/regress/sql/object_address.sql index 1bbe9457c1c..27109d421c7 100644 --- a/src/test/regress/sql/object_address.sql +++ b/src/test/regress/sql/object_address.sql @@ -67,7 +67,9 @@ DECLARE BEGIN FOR objtype IN VALUES ('toast table'), ('index column'), ('sequence column'), ('toast table column'), ('view column'), ('materialized view column'), - ('property graph element'), ('property graph label'), ('property graph property') + ('property graph element'), ('property graph element label'), + ('property graph label'), ('property graph label property'), + ('property graph property') LOOP BEGIN PERFORM pg_get_object_address(objtype, '{one}', '{}'); @@ -282,7 +284,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace -- 2.34.1 --R84XrR4Hgw0dH3Ec-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v2] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-23 09:27 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-23 09:27 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing them to hit the default case and error out with "unsupported object class". During DROP PROPERTY GRAPH, this manifests when an event trigger is active, because pg_event_trigger_ddl_commands() calls these functions. The same code paths are also reachable via pg_identify_object() and pg_identify_object_as_address(). This commit adds the missing cases. Test coverage is added in object_address.sql for these two catalog types via the zero-OID test that exercises pg_identify_object() and pg_identify_object_as_address(). A test in event_trigger.sql verifies that DROP PROPERTY GRAPH works correctly when an event trigger is active. Author: Bertrand Drouvot <[email protected]> Reviewed-by: Michael Paquier <[email protected]> Reviewed-by: Ashutosh Bapat <[email protected]> Discussion: https://postgr.es/m/aej1DkLwhyZWmtxJ@bdtpg --- src/backend/catalog/objectaddress.c | 93 ++++++++++++++++++++ src/test/regress/expected/event_trigger.out | 17 ++++ src/test/regress/expected/object_address.out | 4 + src/test/regress/sql/event_trigger.sql | 13 +++ src/test/regress/sql/object_address.sql | 2 + 5 files changed, 129 insertions(+) 62.4% src/backend/catalog/ 25.6% src/test/regress/expected/ 11.8% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/event_trigger.out b/src/test/regress/expected/event_trigger.out index 065f586310f..ed8d5df397e 100644 --- a/src/test/regress/expected/event_trigger.out +++ b/src/test/regress/expected/event_trigger.out @@ -173,6 +173,23 @@ NOTICE: test_event_trigger: ddl_command_end CREATE USER MAPPING alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; NOTICE: test_event_trigger: ddl_command_end ALTER DEFAULT PRIVILEGES +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE TABLE t2x (i int PRIMARY KEY, j text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); +NOTICE: test_event_trigger: ddl_command_end CREATE PROPERTY GRAPH +DROP PROPERTY GRAPH gx; +NOTICE: test_event_trigger: ddl_command_end DROP PROPERTY GRAPH +DROP TABLE t1x, t2x; +NOTICE: test_event_trigger: ddl_command_end DROP TABLE -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; ERROR: permission denied to change owner of event trigger "regress_event_trigger" diff --git a/src/test/regress/expected/object_address.out b/src/test/regress/expected/object_address.out index 97227d67a54..729c3537f25 100644 --- a/src/test/regress/expected/object_address.out +++ b/src/test/regress/expected/object_address.out @@ -593,7 +593,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace @@ -653,6 +655,8 @@ ORDER BY objects.classid, objects.objid, objects.objsubid; ("(""parameter ACL"",,,)")|("(""parameter ACL"",,)")|NULL ("(""property graph element"",,,)")|("(""property graph element"",,)")|NULL ("(""property graph label"",,,)")|("(""property graph label"",,)")|NULL +("(""property graph element label"",,,)")|("(""property graph element label"",,)")|NULL ("(""property graph property"",,,)")|("(""property graph property"",,)")|NULL +("(""property graph label property"",,,)")|("(""property graph label property"",,)")|NULL -- restore normal output mode \a\t diff --git a/src/test/regress/sql/event_trigger.sql b/src/test/regress/sql/event_trigger.sql index 32e9bb58c5e..271f443378b 100644 --- a/src/test/regress/sql/event_trigger.sql +++ b/src/test/regress/sql/event_trigger.sql @@ -143,6 +143,19 @@ create user mapping for regress_evt_user server useless_server; alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +CREATE TABLE t2x (i int PRIMARY KEY, j text); + +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); + +DROP PROPERTY GRAPH gx; +DROP TABLE t1x, t2x; + -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; diff --git a/src/test/regress/sql/object_address.sql b/src/test/regress/sql/object_address.sql index 1bbe9457c1c..620dacf1045 100644 --- a/src/test/regress/sql/object_address.sql +++ b/src/test/regress/sql/object_address.sql @@ -282,7 +282,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace -- 2.34.1 --gtUR827Uq8d5gVsQ-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v3] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-23 09:27 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-23 09:27 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing them to hit the default case and error out with "unsupported object class". During DROP PROPERTY GRAPH, this manifests when an event trigger is active, because pg_event_trigger_ddl_commands() calls these functions. The same code paths are also reachable via pg_identify_object() and pg_identify_object_as_address(). This commit adds the missing cases. Test coverage is added in object_address.sql for these two catalog types and in create_property_graph.sql covering all property graph object types. A test in event_trigger.sql verifies that DROP PROPERTY GRAPH works correctly when an event trigger is active. Author: Bertrand Drouvot <[email protected]> Reviewed-by: Michael Paquier <[email protected]> Reviewed-by: Ashutosh Bapat <[email protected]> Discussion: https://postgr.es/m/aej1DkLwhyZWmtxJ@bdtpg --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 78 ++++++++++++++++ src/test/regress/expected/event_trigger.out | 17 ++++ src/test/regress/expected/object_address.out | 10 +- .../regress/sql/create_property_graph.sql | 23 +++++ src/test/regress/sql/event_trigger.sql | 13 +++ src/test/regress/sql/object_address.sql | 6 +- 7 files changed, 238 insertions(+), 2 deletions(-) 14.7% src/backend/catalog/ 75.5% src/test/regress/expected/ 9.7% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..eb9e17fb727 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -752,6 +752,84 @@ SELECT (pg_identify_object(classid, objid, objsubid)).* type | create_property_graph_tests | g2 | create_property_graph_tests.g2 (21 rows) +-- test object address functions with recursive dependency walk +-- covers all property graph object types including indirect dependents +SELECT * +FROM ( + WITH RECURSIVE deps (classid, objid, objsubid, refclassid, refobjid, refobjsubid) AS ( + SELECT classid, objid, objsubid, + refclassid, refobjid, refobjsubid + FROM pg_depend + WHERE refclassid = 'pg_class'::regclass AND + refobjid = 'create_property_graph_tests.gt'::regclass + UNION ALL + SELECT d.classid, d.objid, d.objsubid, + d.refclassid, d.refobjid, d.refobjsubid + FROM pg_depend d + JOIN deps dp ON d.refclassid = dp.classid AND d.refobjid = dp.objid AND d.refobjsubid = dp.objsubid + ) + SELECT pg_describe_object(classid, objid, objsubid) as obj, + pg_identify_object(classid, objid, objsubid) as ident, + pg_identify_object_as_address(classid, objid, objsubid) as addr + FROM deps +) s +ORDER BY obj COLLATE "C", ident::text COLLATE "C"; + obj | ident | addr +----------------------------------------------------------+----------------------------------------------------------------------------+---------------------------------------------------------------------------- + edge e of property graph gt | ("property graph element",,,"e of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,e}",{}) + edge e of property graph gt | ("property graph element",,,"e of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,e}",{}) + edge e of property graph gt | ("property graph element",,,"e of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of property graph gt | ("property graph label",,,"e of create_property_graph_tests.gt") | ("property graph label","{create_property_graph_tests,gt,e}",{}) + label v1 of property graph gt | ("property graph label",,,"v1 of create_property_graph_tests.gt") | ("property graph label","{create_property_graph_tests,gt,v1}",{}) + label v1 of vertex v1 of property graph gt | ("property graph element label",,,"v1 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v1}",{}) + label v1 of vertex v1 of property graph gt | ("property graph element label",,,"v1 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v1}",{}) + label v2 of property graph gt | ("property graph label",,,"v2 of create_property_graph_tests.gt") | ("property graph label","{create_property_graph_tests,gt,v2}",{}) + label v2 of vertex v2 of property graph gt | ("property graph element label",,,"v2 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v2}",{}) + label v2 of vertex v2 of property graph gt | ("property graph element label",,,"v2 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v2}",{}) + property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property a of property graph gt | ("property graph property",,,"a of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,a}",{}) + property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property b of property graph gt | ("property graph property",,,"b of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,b}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of property graph gt | ("property graph property",,,"c of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,c}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of property graph gt | ("property graph property",,,"k1 of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,k1}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of property graph gt | ("property graph property",,,"k2 of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,k2}",{}) + property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property m of property graph gt | ("property graph property",,,"m of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,m}",{}) + property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property n of property graph gt | ("property graph property",,,"n of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,n}",{}) + type gt | (type,create_property_graph_tests,gt,create_property_graph_tests.gt) | (type,{create_property_graph_tests.gt},{}) + type gt[] | (type,create_property_graph_tests,_gt,create_property_graph_tests.gt[]) | (type,{create_property_graph_tests.gt[]},{}) + vertex v1 of property graph gt | ("property graph element",,,"v1 of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,v1}",{}) + vertex v2 of property graph gt | ("property graph element",,,"v2 of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,v2}",{}) +(52 rows) + \a\t SELECT pg_get_propgraphdef('g2'::regclass); CREATE PROPERTY GRAPH create_property_graph_tests.g2 diff --git a/src/test/regress/expected/event_trigger.out b/src/test/regress/expected/event_trigger.out index 065f586310f..ed8d5df397e 100644 --- a/src/test/regress/expected/event_trigger.out +++ b/src/test/regress/expected/event_trigger.out @@ -173,6 +173,23 @@ NOTICE: test_event_trigger: ddl_command_end CREATE USER MAPPING alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; NOTICE: test_event_trigger: ddl_command_end ALTER DEFAULT PRIVILEGES +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE TABLE t2x (i int PRIMARY KEY, j text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); +NOTICE: test_event_trigger: ddl_command_end CREATE PROPERTY GRAPH +DROP PROPERTY GRAPH gx; +NOTICE: test_event_trigger: ddl_command_end DROP PROPERTY GRAPH +DROP TABLE t1x, t2x; +NOTICE: test_event_trigger: ddl_command_end DROP TABLE -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; ERROR: permission denied to change owner of event trigger "regress_event_trigger" diff --git a/src/test/regress/expected/object_address.out b/src/test/regress/expected/object_address.out index 97227d67a54..5e53f0b092e 100644 --- a/src/test/regress/expected/object_address.out +++ b/src/test/regress/expected/object_address.out @@ -67,7 +67,9 @@ DECLARE BEGIN FOR objtype IN VALUES ('toast table'), ('index column'), ('sequence column'), ('toast table column'), ('view column'), ('materialized view column'), - ('property graph element'), ('property graph label'), ('property graph property') + ('property graph element'), ('property graph element label'), + ('property graph label'), ('property graph label property'), + ('property graph property') LOOP BEGIN PERFORM pg_get_object_address(objtype, '{one}', '{}'); @@ -84,7 +86,9 @@ WARNING: error for toast table column: unsupported object type "toast table col WARNING: error for view column: unsupported object type "view column" WARNING: error for materialized view column: unsupported object type "materialized view column" WARNING: error for property graph element: unsupported object type "property graph element" +WARNING: error for property graph element label: unrecognized object type "property graph element label" WARNING: error for property graph label: unsupported object type "property graph label" +WARNING: error for property graph label property: unrecognized object type "property graph label property" WARNING: error for property graph property: unsupported object type "property graph property" -- miscellaneous other errors select * from pg_get_object_address('operator of access method', '{btree,integer_ops,1}', '{int4,bool}'); @@ -593,7 +597,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace @@ -653,6 +659,8 @@ ORDER BY objects.classid, objects.objid, objects.objsubid; ("(""parameter ACL"",,,)")|("(""parameter ACL"",,)")|NULL ("(""property graph element"",,,)")|("(""property graph element"",,)")|NULL ("(""property graph label"",,,)")|("(""property graph label"",,)")|NULL +("(""property graph element label"",,,)")|("(""property graph element label"",,)")|NULL ("(""property graph property"",,,)")|("(""property graph property"",,)")|NULL +("(""property graph label property"",,,)")|("(""property graph label property"",,)")|NULL -- restore normal output mode \a\t diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..9608dd5c4af 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -298,6 +298,29 @@ SELECT (pg_identify_object(classid, objid, objsubid)).* refobjid = 'create_property_graph_tests.g2'::regclass ORDER BY 1, 2, 3, 4; +-- test object address functions with recursive dependency walk +-- covers all property graph object types including indirect dependents +SELECT * +FROM ( + WITH RECURSIVE deps (classid, objid, objsubid, refclassid, refobjid, refobjsubid) AS ( + SELECT classid, objid, objsubid, + refclassid, refobjid, refobjsubid + FROM pg_depend + WHERE refclassid = 'pg_class'::regclass AND + refobjid = 'create_property_graph_tests.gt'::regclass + UNION ALL + SELECT d.classid, d.objid, d.objsubid, + d.refclassid, d.refobjid, d.refobjsubid + FROM pg_depend d + JOIN deps dp ON d.refclassid = dp.classid AND d.refobjid = dp.objid AND d.refobjsubid = dp.objsubid + ) + SELECT pg_describe_object(classid, objid, objsubid) as obj, + pg_identify_object(classid, objid, objsubid) as ident, + pg_identify_object_as_address(classid, objid, objsubid) as addr + FROM deps +) s +ORDER BY obj COLLATE "C", ident::text COLLATE "C"; + \a\t SELECT pg_get_propgraphdef('g2'::regclass); SELECT pg_get_propgraphdef('g3'::regclass); diff --git a/src/test/regress/sql/event_trigger.sql b/src/test/regress/sql/event_trigger.sql index 32e9bb58c5e..271f443378b 100644 --- a/src/test/regress/sql/event_trigger.sql +++ b/src/test/regress/sql/event_trigger.sql @@ -143,6 +143,19 @@ create user mapping for regress_evt_user server useless_server; alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +CREATE TABLE t2x (i int PRIMARY KEY, j text); + +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); + +DROP PROPERTY GRAPH gx; +DROP TABLE t1x, t2x; + -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; diff --git a/src/test/regress/sql/object_address.sql b/src/test/regress/sql/object_address.sql index 1bbe9457c1c..27109d421c7 100644 --- a/src/test/regress/sql/object_address.sql +++ b/src/test/regress/sql/object_address.sql @@ -67,7 +67,9 @@ DECLARE BEGIN FOR objtype IN VALUES ('toast table'), ('index column'), ('sequence column'), ('toast table column'), ('view column'), ('materialized view column'), - ('property graph element'), ('property graph label'), ('property graph property') + ('property graph element'), ('property graph element label'), + ('property graph label'), ('property graph label property'), + ('property graph property') LOOP BEGIN PERFORM pg_get_object_address(objtype, '{one}', '{}'); @@ -282,7 +284,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace -- 2.34.1 --R84XrR4Hgw0dH3Ec-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v3] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-23 09:27 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-23 09:27 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing them to hit the default case and error out with "unsupported object class". During DROP PROPERTY GRAPH, this manifests when an event trigger is active, because pg_event_trigger_ddl_commands() calls these functions. The same code paths are also reachable via pg_identify_object() and pg_identify_object_as_address(). This commit adds the missing cases. Test coverage is added in object_address.sql for these two catalog types and in create_property_graph.sql covering all property graph object types. A test in event_trigger.sql verifies that DROP PROPERTY GRAPH works correctly when an event trigger is active. Author: Bertrand Drouvot <[email protected]> Reviewed-by: Michael Paquier <[email protected]> Reviewed-by: Ashutosh Bapat <[email protected]> Discussion: https://postgr.es/m/aej1DkLwhyZWmtxJ@bdtpg --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 78 ++++++++++++++++ src/test/regress/expected/event_trigger.out | 17 ++++ src/test/regress/expected/object_address.out | 10 +- .../regress/sql/create_property_graph.sql | 23 +++++ src/test/regress/sql/event_trigger.sql | 13 +++ src/test/regress/sql/object_address.sql | 6 +- 7 files changed, 238 insertions(+), 2 deletions(-) 14.7% src/backend/catalog/ 75.5% src/test/regress/expected/ 9.7% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..eb9e17fb727 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -752,6 +752,84 @@ SELECT (pg_identify_object(classid, objid, objsubid)).* type | create_property_graph_tests | g2 | create_property_graph_tests.g2 (21 rows) +-- test object address functions with recursive dependency walk +-- covers all property graph object types including indirect dependents +SELECT * +FROM ( + WITH RECURSIVE deps (classid, objid, objsubid, refclassid, refobjid, refobjsubid) AS ( + SELECT classid, objid, objsubid, + refclassid, refobjid, refobjsubid + FROM pg_depend + WHERE refclassid = 'pg_class'::regclass AND + refobjid = 'create_property_graph_tests.gt'::regclass + UNION ALL + SELECT d.classid, d.objid, d.objsubid, + d.refclassid, d.refobjid, d.refobjsubid + FROM pg_depend d + JOIN deps dp ON d.refclassid = dp.classid AND d.refobjid = dp.objid AND d.refobjsubid = dp.objsubid + ) + SELECT pg_describe_object(classid, objid, objsubid) as obj, + pg_identify_object(classid, objid, objsubid) as ident, + pg_identify_object_as_address(classid, objid, objsubid) as addr + FROM deps +) s +ORDER BY obj COLLATE "C", ident::text COLLATE "C"; + obj | ident | addr +----------------------------------------------------------+----------------------------------------------------------------------------+---------------------------------------------------------------------------- + edge e of property graph gt | ("property graph element",,,"e of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,e}",{}) + edge e of property graph gt | ("property graph element",,,"e of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,e}",{}) + edge e of property graph gt | ("property graph element",,,"e of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of property graph gt | ("property graph label",,,"e of create_property_graph_tests.gt") | ("property graph label","{create_property_graph_tests,gt,e}",{}) + label v1 of property graph gt | ("property graph label",,,"v1 of create_property_graph_tests.gt") | ("property graph label","{create_property_graph_tests,gt,v1}",{}) + label v1 of vertex v1 of property graph gt | ("property graph element label",,,"v1 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v1}",{}) + label v1 of vertex v1 of property graph gt | ("property graph element label",,,"v1 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v1}",{}) + label v2 of property graph gt | ("property graph label",,,"v2 of create_property_graph_tests.gt") | ("property graph label","{create_property_graph_tests,gt,v2}",{}) + label v2 of vertex v2 of property graph gt | ("property graph element label",,,"v2 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v2}",{}) + label v2 of vertex v2 of property graph gt | ("property graph element label",,,"v2 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v2}",{}) + property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property a of property graph gt | ("property graph property",,,"a of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,a}",{}) + property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property b of property graph gt | ("property graph property",,,"b of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,b}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of property graph gt | ("property graph property",,,"c of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,c}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of property graph gt | ("property graph property",,,"k1 of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,k1}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of property graph gt | ("property graph property",,,"k2 of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,k2}",{}) + property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property m of property graph gt | ("property graph property",,,"m of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,m}",{}) + property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property n of property graph gt | ("property graph property",,,"n of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,n}",{}) + type gt | (type,create_property_graph_tests,gt,create_property_graph_tests.gt) | (type,{create_property_graph_tests.gt},{}) + type gt[] | (type,create_property_graph_tests,_gt,create_property_graph_tests.gt[]) | (type,{create_property_graph_tests.gt[]},{}) + vertex v1 of property graph gt | ("property graph element",,,"v1 of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,v1}",{}) + vertex v2 of property graph gt | ("property graph element",,,"v2 of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,v2}",{}) +(52 rows) + \a\t SELECT pg_get_propgraphdef('g2'::regclass); CREATE PROPERTY GRAPH create_property_graph_tests.g2 diff --git a/src/test/regress/expected/event_trigger.out b/src/test/regress/expected/event_trigger.out index 065f586310f..ed8d5df397e 100644 --- a/src/test/regress/expected/event_trigger.out +++ b/src/test/regress/expected/event_trigger.out @@ -173,6 +173,23 @@ NOTICE: test_event_trigger: ddl_command_end CREATE USER MAPPING alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; NOTICE: test_event_trigger: ddl_command_end ALTER DEFAULT PRIVILEGES +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE TABLE t2x (i int PRIMARY KEY, j text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); +NOTICE: test_event_trigger: ddl_command_end CREATE PROPERTY GRAPH +DROP PROPERTY GRAPH gx; +NOTICE: test_event_trigger: ddl_command_end DROP PROPERTY GRAPH +DROP TABLE t1x, t2x; +NOTICE: test_event_trigger: ddl_command_end DROP TABLE -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; ERROR: permission denied to change owner of event trigger "regress_event_trigger" diff --git a/src/test/regress/expected/object_address.out b/src/test/regress/expected/object_address.out index 97227d67a54..5e53f0b092e 100644 --- a/src/test/regress/expected/object_address.out +++ b/src/test/regress/expected/object_address.out @@ -67,7 +67,9 @@ DECLARE BEGIN FOR objtype IN VALUES ('toast table'), ('index column'), ('sequence column'), ('toast table column'), ('view column'), ('materialized view column'), - ('property graph element'), ('property graph label'), ('property graph property') + ('property graph element'), ('property graph element label'), + ('property graph label'), ('property graph label property'), + ('property graph property') LOOP BEGIN PERFORM pg_get_object_address(objtype, '{one}', '{}'); @@ -84,7 +86,9 @@ WARNING: error for toast table column: unsupported object type "toast table col WARNING: error for view column: unsupported object type "view column" WARNING: error for materialized view column: unsupported object type "materialized view column" WARNING: error for property graph element: unsupported object type "property graph element" +WARNING: error for property graph element label: unrecognized object type "property graph element label" WARNING: error for property graph label: unsupported object type "property graph label" +WARNING: error for property graph label property: unrecognized object type "property graph label property" WARNING: error for property graph property: unsupported object type "property graph property" -- miscellaneous other errors select * from pg_get_object_address('operator of access method', '{btree,integer_ops,1}', '{int4,bool}'); @@ -593,7 +597,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace @@ -653,6 +659,8 @@ ORDER BY objects.classid, objects.objid, objects.objsubid; ("(""parameter ACL"",,,)")|("(""parameter ACL"",,)")|NULL ("(""property graph element"",,,)")|("(""property graph element"",,)")|NULL ("(""property graph label"",,,)")|("(""property graph label"",,)")|NULL +("(""property graph element label"",,,)")|("(""property graph element label"",,)")|NULL ("(""property graph property"",,,)")|("(""property graph property"",,)")|NULL +("(""property graph label property"",,,)")|("(""property graph label property"",,)")|NULL -- restore normal output mode \a\t diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..9608dd5c4af 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -298,6 +298,29 @@ SELECT (pg_identify_object(classid, objid, objsubid)).* refobjid = 'create_property_graph_tests.g2'::regclass ORDER BY 1, 2, 3, 4; +-- test object address functions with recursive dependency walk +-- covers all property graph object types including indirect dependents +SELECT * +FROM ( + WITH RECURSIVE deps (classid, objid, objsubid, refclassid, refobjid, refobjsubid) AS ( + SELECT classid, objid, objsubid, + refclassid, refobjid, refobjsubid + FROM pg_depend + WHERE refclassid = 'pg_class'::regclass AND + refobjid = 'create_property_graph_tests.gt'::regclass + UNION ALL + SELECT d.classid, d.objid, d.objsubid, + d.refclassid, d.refobjid, d.refobjsubid + FROM pg_depend d + JOIN deps dp ON d.refclassid = dp.classid AND d.refobjid = dp.objid AND d.refobjsubid = dp.objsubid + ) + SELECT pg_describe_object(classid, objid, objsubid) as obj, + pg_identify_object(classid, objid, objsubid) as ident, + pg_identify_object_as_address(classid, objid, objsubid) as addr + FROM deps +) s +ORDER BY obj COLLATE "C", ident::text COLLATE "C"; + \a\t SELECT pg_get_propgraphdef('g2'::regclass); SELECT pg_get_propgraphdef('g3'::regclass); diff --git a/src/test/regress/sql/event_trigger.sql b/src/test/regress/sql/event_trigger.sql index 32e9bb58c5e..271f443378b 100644 --- a/src/test/regress/sql/event_trigger.sql +++ b/src/test/regress/sql/event_trigger.sql @@ -143,6 +143,19 @@ create user mapping for regress_evt_user server useless_server; alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +CREATE TABLE t2x (i int PRIMARY KEY, j text); + +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); + +DROP PROPERTY GRAPH gx; +DROP TABLE t1x, t2x; + -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; diff --git a/src/test/regress/sql/object_address.sql b/src/test/regress/sql/object_address.sql index 1bbe9457c1c..27109d421c7 100644 --- a/src/test/regress/sql/object_address.sql +++ b/src/test/regress/sql/object_address.sql @@ -67,7 +67,9 @@ DECLARE BEGIN FOR objtype IN VALUES ('toast table'), ('index column'), ('sequence column'), ('toast table column'), ('view column'), ('materialized view column'), - ('property graph element'), ('property graph label'), ('property graph property') + ('property graph element'), ('property graph element label'), + ('property graph label'), ('property graph label property'), + ('property graph property') LOOP BEGIN PERFORM pg_get_object_address(objtype, '{one}', '{}'); @@ -282,7 +284,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace -- 2.34.1 --R84XrR4Hgw0dH3Ec-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v2] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-23 09:27 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-23 09:27 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing them to hit the default case and error out with "unsupported object class". During DROP PROPERTY GRAPH, this manifests when an event trigger is active, because pg_event_trigger_ddl_commands() calls these functions. The same code paths are also reachable via pg_identify_object() and pg_identify_object_as_address(). This commit adds the missing cases. Test coverage is added in object_address.sql for these two catalog types via the zero-OID test that exercises pg_identify_object() and pg_identify_object_as_address(). A test in event_trigger.sql verifies that DROP PROPERTY GRAPH works correctly when an event trigger is active. Author: Bertrand Drouvot <[email protected]> Reviewed-by: Michael Paquier <[email protected]> Reviewed-by: Ashutosh Bapat <[email protected]> Discussion: https://postgr.es/m/aej1DkLwhyZWmtxJ@bdtpg --- src/backend/catalog/objectaddress.c | 93 ++++++++++++++++++++ src/test/regress/expected/event_trigger.out | 17 ++++ src/test/regress/expected/object_address.out | 4 + src/test/regress/sql/event_trigger.sql | 13 +++ src/test/regress/sql/object_address.sql | 2 + 5 files changed, 129 insertions(+) 62.4% src/backend/catalog/ 25.6% src/test/regress/expected/ 11.8% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/event_trigger.out b/src/test/regress/expected/event_trigger.out index 065f586310f..ed8d5df397e 100644 --- a/src/test/regress/expected/event_trigger.out +++ b/src/test/regress/expected/event_trigger.out @@ -173,6 +173,23 @@ NOTICE: test_event_trigger: ddl_command_end CREATE USER MAPPING alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; NOTICE: test_event_trigger: ddl_command_end ALTER DEFAULT PRIVILEGES +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE TABLE t2x (i int PRIMARY KEY, j text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); +NOTICE: test_event_trigger: ddl_command_end CREATE PROPERTY GRAPH +DROP PROPERTY GRAPH gx; +NOTICE: test_event_trigger: ddl_command_end DROP PROPERTY GRAPH +DROP TABLE t1x, t2x; +NOTICE: test_event_trigger: ddl_command_end DROP TABLE -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; ERROR: permission denied to change owner of event trigger "regress_event_trigger" diff --git a/src/test/regress/expected/object_address.out b/src/test/regress/expected/object_address.out index 97227d67a54..729c3537f25 100644 --- a/src/test/regress/expected/object_address.out +++ b/src/test/regress/expected/object_address.out @@ -593,7 +593,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace @@ -653,6 +655,8 @@ ORDER BY objects.classid, objects.objid, objects.objsubid; ("(""parameter ACL"",,,)")|("(""parameter ACL"",,)")|NULL ("(""property graph element"",,,)")|("(""property graph element"",,)")|NULL ("(""property graph label"",,,)")|("(""property graph label"",,)")|NULL +("(""property graph element label"",,,)")|("(""property graph element label"",,)")|NULL ("(""property graph property"",,,)")|("(""property graph property"",,)")|NULL +("(""property graph label property"",,,)")|("(""property graph label property"",,)")|NULL -- restore normal output mode \a\t diff --git a/src/test/regress/sql/event_trigger.sql b/src/test/regress/sql/event_trigger.sql index 32e9bb58c5e..271f443378b 100644 --- a/src/test/regress/sql/event_trigger.sql +++ b/src/test/regress/sql/event_trigger.sql @@ -143,6 +143,19 @@ create user mapping for regress_evt_user server useless_server; alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +CREATE TABLE t2x (i int PRIMARY KEY, j text); + +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); + +DROP PROPERTY GRAPH gx; +DROP TABLE t1x, t2x; + -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; diff --git a/src/test/regress/sql/object_address.sql b/src/test/regress/sql/object_address.sql index 1bbe9457c1c..620dacf1045 100644 --- a/src/test/regress/sql/object_address.sql +++ b/src/test/regress/sql/object_address.sql @@ -282,7 +282,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace -- 2.34.1 --gtUR827Uq8d5gVsQ-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v2] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-23 09:27 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-23 09:27 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing them to hit the default case and error out with "unsupported object class". During DROP PROPERTY GRAPH, this manifests when an event trigger is active, because pg_event_trigger_ddl_commands() calls these functions. The same code paths are also reachable via pg_identify_object() and pg_identify_object_as_address(). This commit adds the missing cases. Test coverage is added in object_address.sql for these two catalog types via the zero-OID test that exercises pg_identify_object() and pg_identify_object_as_address(). A test in event_trigger.sql verifies that DROP PROPERTY GRAPH works correctly when an event trigger is active. Author: Bertrand Drouvot <[email protected]> Reviewed-by: Michael Paquier <[email protected]> Reviewed-by: Ashutosh Bapat <[email protected]> Discussion: https://postgr.es/m/aej1DkLwhyZWmtxJ@bdtpg --- src/backend/catalog/objectaddress.c | 93 ++++++++++++++++++++ src/test/regress/expected/event_trigger.out | 17 ++++ src/test/regress/expected/object_address.out | 4 + src/test/regress/sql/event_trigger.sql | 13 +++ src/test/regress/sql/object_address.sql | 2 + 5 files changed, 129 insertions(+) 62.4% src/backend/catalog/ 25.6% src/test/regress/expected/ 11.8% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/event_trigger.out b/src/test/regress/expected/event_trigger.out index 065f586310f..ed8d5df397e 100644 --- a/src/test/regress/expected/event_trigger.out +++ b/src/test/regress/expected/event_trigger.out @@ -173,6 +173,23 @@ NOTICE: test_event_trigger: ddl_command_end CREATE USER MAPPING alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; NOTICE: test_event_trigger: ddl_command_end ALTER DEFAULT PRIVILEGES +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE TABLE t2x (i int PRIMARY KEY, j text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); +NOTICE: test_event_trigger: ddl_command_end CREATE PROPERTY GRAPH +DROP PROPERTY GRAPH gx; +NOTICE: test_event_trigger: ddl_command_end DROP PROPERTY GRAPH +DROP TABLE t1x, t2x; +NOTICE: test_event_trigger: ddl_command_end DROP TABLE -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; ERROR: permission denied to change owner of event trigger "regress_event_trigger" diff --git a/src/test/regress/expected/object_address.out b/src/test/regress/expected/object_address.out index 97227d67a54..729c3537f25 100644 --- a/src/test/regress/expected/object_address.out +++ b/src/test/regress/expected/object_address.out @@ -593,7 +593,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace @@ -653,6 +655,8 @@ ORDER BY objects.classid, objects.objid, objects.objsubid; ("(""parameter ACL"",,,)")|("(""parameter ACL"",,)")|NULL ("(""property graph element"",,,)")|("(""property graph element"",,)")|NULL ("(""property graph label"",,,)")|("(""property graph label"",,)")|NULL +("(""property graph element label"",,,)")|("(""property graph element label"",,)")|NULL ("(""property graph property"",,,)")|("(""property graph property"",,)")|NULL +("(""property graph label property"",,,)")|("(""property graph label property"",,)")|NULL -- restore normal output mode \a\t diff --git a/src/test/regress/sql/event_trigger.sql b/src/test/regress/sql/event_trigger.sql index 32e9bb58c5e..271f443378b 100644 --- a/src/test/regress/sql/event_trigger.sql +++ b/src/test/regress/sql/event_trigger.sql @@ -143,6 +143,19 @@ create user mapping for regress_evt_user server useless_server; alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +CREATE TABLE t2x (i int PRIMARY KEY, j text); + +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); + +DROP PROPERTY GRAPH gx; +DROP TABLE t1x, t2x; + -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; diff --git a/src/test/regress/sql/object_address.sql b/src/test/regress/sql/object_address.sql index 1bbe9457c1c..620dacf1045 100644 --- a/src/test/regress/sql/object_address.sql +++ b/src/test/regress/sql/object_address.sql @@ -282,7 +282,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace -- 2.34.1 --gtUR827Uq8d5gVsQ-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v2] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-23 09:27 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-23 09:27 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing them to hit the default case and error out with "unsupported object class". During DROP PROPERTY GRAPH, this manifests when an event trigger is active, because pg_event_trigger_ddl_commands() calls these functions. The same code paths are also reachable via pg_identify_object() and pg_identify_object_as_address(). This commit adds the missing cases. Test coverage is added in object_address.sql for these two catalog types via the zero-OID test that exercises pg_identify_object() and pg_identify_object_as_address(). A test in event_trigger.sql verifies that DROP PROPERTY GRAPH works correctly when an event trigger is active. Author: Bertrand Drouvot <[email protected]> Reviewed-by: Michael Paquier <[email protected]> Reviewed-by: Ashutosh Bapat <[email protected]> Discussion: https://postgr.es/m/aej1DkLwhyZWmtxJ@bdtpg --- src/backend/catalog/objectaddress.c | 93 ++++++++++++++++++++ src/test/regress/expected/event_trigger.out | 17 ++++ src/test/regress/expected/object_address.out | 4 + src/test/regress/sql/event_trigger.sql | 13 +++ src/test/regress/sql/object_address.sql | 2 + 5 files changed, 129 insertions(+) 62.4% src/backend/catalog/ 25.6% src/test/regress/expected/ 11.8% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/event_trigger.out b/src/test/regress/expected/event_trigger.out index 065f586310f..ed8d5df397e 100644 --- a/src/test/regress/expected/event_trigger.out +++ b/src/test/regress/expected/event_trigger.out @@ -173,6 +173,23 @@ NOTICE: test_event_trigger: ddl_command_end CREATE USER MAPPING alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; NOTICE: test_event_trigger: ddl_command_end ALTER DEFAULT PRIVILEGES +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE TABLE t2x (i int PRIMARY KEY, j text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); +NOTICE: test_event_trigger: ddl_command_end CREATE PROPERTY GRAPH +DROP PROPERTY GRAPH gx; +NOTICE: test_event_trigger: ddl_command_end DROP PROPERTY GRAPH +DROP TABLE t1x, t2x; +NOTICE: test_event_trigger: ddl_command_end DROP TABLE -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; ERROR: permission denied to change owner of event trigger "regress_event_trigger" diff --git a/src/test/regress/expected/object_address.out b/src/test/regress/expected/object_address.out index 97227d67a54..729c3537f25 100644 --- a/src/test/regress/expected/object_address.out +++ b/src/test/regress/expected/object_address.out @@ -593,7 +593,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace @@ -653,6 +655,8 @@ ORDER BY objects.classid, objects.objid, objects.objsubid; ("(""parameter ACL"",,,)")|("(""parameter ACL"",,)")|NULL ("(""property graph element"",,,)")|("(""property graph element"",,)")|NULL ("(""property graph label"",,,)")|("(""property graph label"",,)")|NULL +("(""property graph element label"",,,)")|("(""property graph element label"",,)")|NULL ("(""property graph property"",,,)")|("(""property graph property"",,)")|NULL +("(""property graph label property"",,,)")|("(""property graph label property"",,)")|NULL -- restore normal output mode \a\t diff --git a/src/test/regress/sql/event_trigger.sql b/src/test/regress/sql/event_trigger.sql index 32e9bb58c5e..271f443378b 100644 --- a/src/test/regress/sql/event_trigger.sql +++ b/src/test/regress/sql/event_trigger.sql @@ -143,6 +143,19 @@ create user mapping for regress_evt_user server useless_server; alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +CREATE TABLE t2x (i int PRIMARY KEY, j text); + +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); + +DROP PROPERTY GRAPH gx; +DROP TABLE t1x, t2x; + -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; diff --git a/src/test/regress/sql/object_address.sql b/src/test/regress/sql/object_address.sql index 1bbe9457c1c..620dacf1045 100644 --- a/src/test/regress/sql/object_address.sql +++ b/src/test/regress/sql/object_address.sql @@ -282,7 +282,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace -- 2.34.1 --gtUR827Uq8d5gVsQ-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v2] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-23 09:27 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-23 09:27 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing them to hit the default case and error out with "unsupported object class". During DROP PROPERTY GRAPH, this manifests when an event trigger is active, because pg_event_trigger_ddl_commands() calls these functions. The same code paths are also reachable via pg_identify_object() and pg_identify_object_as_address(). This commit adds the missing cases. Test coverage is added in object_address.sql for these two catalog types via the zero-OID test that exercises pg_identify_object() and pg_identify_object_as_address(). A test in event_trigger.sql verifies that DROP PROPERTY GRAPH works correctly when an event trigger is active. Author: Bertrand Drouvot <[email protected]> Reviewed-by: Michael Paquier <[email protected]> Reviewed-by: Ashutosh Bapat <[email protected]> Discussion: https://postgr.es/m/aej1DkLwhyZWmtxJ@bdtpg --- src/backend/catalog/objectaddress.c | 93 ++++++++++++++++++++ src/test/regress/expected/event_trigger.out | 17 ++++ src/test/regress/expected/object_address.out | 4 + src/test/regress/sql/event_trigger.sql | 13 +++ src/test/regress/sql/object_address.sql | 2 + 5 files changed, 129 insertions(+) 62.4% src/backend/catalog/ 25.6% src/test/regress/expected/ 11.8% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/event_trigger.out b/src/test/regress/expected/event_trigger.out index 065f586310f..ed8d5df397e 100644 --- a/src/test/regress/expected/event_trigger.out +++ b/src/test/regress/expected/event_trigger.out @@ -173,6 +173,23 @@ NOTICE: test_event_trigger: ddl_command_end CREATE USER MAPPING alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; NOTICE: test_event_trigger: ddl_command_end ALTER DEFAULT PRIVILEGES +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE TABLE t2x (i int PRIMARY KEY, j text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); +NOTICE: test_event_trigger: ddl_command_end CREATE PROPERTY GRAPH +DROP PROPERTY GRAPH gx; +NOTICE: test_event_trigger: ddl_command_end DROP PROPERTY GRAPH +DROP TABLE t1x, t2x; +NOTICE: test_event_trigger: ddl_command_end DROP TABLE -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; ERROR: permission denied to change owner of event trigger "regress_event_trigger" diff --git a/src/test/regress/expected/object_address.out b/src/test/regress/expected/object_address.out index 97227d67a54..729c3537f25 100644 --- a/src/test/regress/expected/object_address.out +++ b/src/test/regress/expected/object_address.out @@ -593,7 +593,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace @@ -653,6 +655,8 @@ ORDER BY objects.classid, objects.objid, objects.objsubid; ("(""parameter ACL"",,,)")|("(""parameter ACL"",,)")|NULL ("(""property graph element"",,,)")|("(""property graph element"",,)")|NULL ("(""property graph label"",,,)")|("(""property graph label"",,)")|NULL +("(""property graph element label"",,,)")|("(""property graph element label"",,)")|NULL ("(""property graph property"",,,)")|("(""property graph property"",,)")|NULL +("(""property graph label property"",,,)")|("(""property graph label property"",,)")|NULL -- restore normal output mode \a\t diff --git a/src/test/regress/sql/event_trigger.sql b/src/test/regress/sql/event_trigger.sql index 32e9bb58c5e..271f443378b 100644 --- a/src/test/regress/sql/event_trigger.sql +++ b/src/test/regress/sql/event_trigger.sql @@ -143,6 +143,19 @@ create user mapping for regress_evt_user server useless_server; alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +CREATE TABLE t2x (i int PRIMARY KEY, j text); + +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); + +DROP PROPERTY GRAPH gx; +DROP TABLE t1x, t2x; + -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; diff --git a/src/test/regress/sql/object_address.sql b/src/test/regress/sql/object_address.sql index 1bbe9457c1c..620dacf1045 100644 --- a/src/test/regress/sql/object_address.sql +++ b/src/test/regress/sql/object_address.sql @@ -282,7 +282,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace -- 2.34.1 --gtUR827Uq8d5gVsQ-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v2] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-23 09:27 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-23 09:27 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing them to hit the default case and error out with "unsupported object class". During DROP PROPERTY GRAPH, this manifests when an event trigger is active, because pg_event_trigger_ddl_commands() calls these functions. The same code paths are also reachable via pg_identify_object() and pg_identify_object_as_address(). This commit adds the missing cases. Test coverage is added in object_address.sql for these two catalog types via the zero-OID test that exercises pg_identify_object() and pg_identify_object_as_address(). A test in event_trigger.sql verifies that DROP PROPERTY GRAPH works correctly when an event trigger is active. Author: Bertrand Drouvot <[email protected]> Reviewed-by: Michael Paquier <[email protected]> Reviewed-by: Ashutosh Bapat <[email protected]> Discussion: https://postgr.es/m/aej1DkLwhyZWmtxJ@bdtpg --- src/backend/catalog/objectaddress.c | 93 ++++++++++++++++++++ src/test/regress/expected/event_trigger.out | 17 ++++ src/test/regress/expected/object_address.out | 4 + src/test/regress/sql/event_trigger.sql | 13 +++ src/test/regress/sql/object_address.sql | 2 + 5 files changed, 129 insertions(+) 62.4% src/backend/catalog/ 25.6% src/test/regress/expected/ 11.8% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/event_trigger.out b/src/test/regress/expected/event_trigger.out index 065f586310f..ed8d5df397e 100644 --- a/src/test/regress/expected/event_trigger.out +++ b/src/test/regress/expected/event_trigger.out @@ -173,6 +173,23 @@ NOTICE: test_event_trigger: ddl_command_end CREATE USER MAPPING alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; NOTICE: test_event_trigger: ddl_command_end ALTER DEFAULT PRIVILEGES +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE TABLE t2x (i int PRIMARY KEY, j text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); +NOTICE: test_event_trigger: ddl_command_end CREATE PROPERTY GRAPH +DROP PROPERTY GRAPH gx; +NOTICE: test_event_trigger: ddl_command_end DROP PROPERTY GRAPH +DROP TABLE t1x, t2x; +NOTICE: test_event_trigger: ddl_command_end DROP TABLE -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; ERROR: permission denied to change owner of event trigger "regress_event_trigger" diff --git a/src/test/regress/expected/object_address.out b/src/test/regress/expected/object_address.out index 97227d67a54..729c3537f25 100644 --- a/src/test/regress/expected/object_address.out +++ b/src/test/regress/expected/object_address.out @@ -593,7 +593,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace @@ -653,6 +655,8 @@ ORDER BY objects.classid, objects.objid, objects.objsubid; ("(""parameter ACL"",,,)")|("(""parameter ACL"",,)")|NULL ("(""property graph element"",,,)")|("(""property graph element"",,)")|NULL ("(""property graph label"",,,)")|("(""property graph label"",,)")|NULL +("(""property graph element label"",,,)")|("(""property graph element label"",,)")|NULL ("(""property graph property"",,,)")|("(""property graph property"",,)")|NULL +("(""property graph label property"",,,)")|("(""property graph label property"",,)")|NULL -- restore normal output mode \a\t diff --git a/src/test/regress/sql/event_trigger.sql b/src/test/regress/sql/event_trigger.sql index 32e9bb58c5e..271f443378b 100644 --- a/src/test/regress/sql/event_trigger.sql +++ b/src/test/regress/sql/event_trigger.sql @@ -143,6 +143,19 @@ create user mapping for regress_evt_user server useless_server; alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +CREATE TABLE t2x (i int PRIMARY KEY, j text); + +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); + +DROP PROPERTY GRAPH gx; +DROP TABLE t1x, t2x; + -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; diff --git a/src/test/regress/sql/object_address.sql b/src/test/regress/sql/object_address.sql index 1bbe9457c1c..620dacf1045 100644 --- a/src/test/regress/sql/object_address.sql +++ b/src/test/regress/sql/object_address.sql @@ -282,7 +282,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace -- 2.34.1 --gtUR827Uq8d5gVsQ-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v2] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-23 09:27 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-23 09:27 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing them to hit the default case and error out with "unsupported object class". During DROP PROPERTY GRAPH, this manifests when an event trigger is active, because pg_event_trigger_ddl_commands() calls these functions. The same code paths are also reachable via pg_identify_object() and pg_identify_object_as_address(). This commit adds the missing cases. Test coverage is added in object_address.sql for these two catalog types via the zero-OID test that exercises pg_identify_object() and pg_identify_object_as_address(). A test in event_trigger.sql verifies that DROP PROPERTY GRAPH works correctly when an event trigger is active. Author: Bertrand Drouvot <[email protected]> Reviewed-by: Michael Paquier <[email protected]> Reviewed-by: Ashutosh Bapat <[email protected]> Discussion: https://postgr.es/m/aej1DkLwhyZWmtxJ@bdtpg --- src/backend/catalog/objectaddress.c | 93 ++++++++++++++++++++ src/test/regress/expected/event_trigger.out | 17 ++++ src/test/regress/expected/object_address.out | 4 + src/test/regress/sql/event_trigger.sql | 13 +++ src/test/regress/sql/object_address.sql | 2 + 5 files changed, 129 insertions(+) 62.4% src/backend/catalog/ 25.6% src/test/regress/expected/ 11.8% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/event_trigger.out b/src/test/regress/expected/event_trigger.out index 065f586310f..ed8d5df397e 100644 --- a/src/test/regress/expected/event_trigger.out +++ b/src/test/regress/expected/event_trigger.out @@ -173,6 +173,23 @@ NOTICE: test_event_trigger: ddl_command_end CREATE USER MAPPING alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; NOTICE: test_event_trigger: ddl_command_end ALTER DEFAULT PRIVILEGES +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE TABLE t2x (i int PRIMARY KEY, j text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); +NOTICE: test_event_trigger: ddl_command_end CREATE PROPERTY GRAPH +DROP PROPERTY GRAPH gx; +NOTICE: test_event_trigger: ddl_command_end DROP PROPERTY GRAPH +DROP TABLE t1x, t2x; +NOTICE: test_event_trigger: ddl_command_end DROP TABLE -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; ERROR: permission denied to change owner of event trigger "regress_event_trigger" diff --git a/src/test/regress/expected/object_address.out b/src/test/regress/expected/object_address.out index 97227d67a54..729c3537f25 100644 --- a/src/test/regress/expected/object_address.out +++ b/src/test/regress/expected/object_address.out @@ -593,7 +593,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace @@ -653,6 +655,8 @@ ORDER BY objects.classid, objects.objid, objects.objsubid; ("(""parameter ACL"",,,)")|("(""parameter ACL"",,)")|NULL ("(""property graph element"",,,)")|("(""property graph element"",,)")|NULL ("(""property graph label"",,,)")|("(""property graph label"",,)")|NULL +("(""property graph element label"",,,)")|("(""property graph element label"",,)")|NULL ("(""property graph property"",,,)")|("(""property graph property"",,)")|NULL +("(""property graph label property"",,,)")|("(""property graph label property"",,)")|NULL -- restore normal output mode \a\t diff --git a/src/test/regress/sql/event_trigger.sql b/src/test/regress/sql/event_trigger.sql index 32e9bb58c5e..271f443378b 100644 --- a/src/test/regress/sql/event_trigger.sql +++ b/src/test/regress/sql/event_trigger.sql @@ -143,6 +143,19 @@ create user mapping for regress_evt_user server useless_server; alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +CREATE TABLE t2x (i int PRIMARY KEY, j text); + +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); + +DROP PROPERTY GRAPH gx; +DROP TABLE t1x, t2x; + -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; diff --git a/src/test/regress/sql/object_address.sql b/src/test/regress/sql/object_address.sql index 1bbe9457c1c..620dacf1045 100644 --- a/src/test/regress/sql/object_address.sql +++ b/src/test/regress/sql/object_address.sql @@ -282,7 +282,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace -- 2.34.1 --gtUR827Uq8d5gVsQ-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v3] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-23 09:27 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-23 09:27 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing them to hit the default case and error out with "unsupported object class". During DROP PROPERTY GRAPH, this manifests when an event trigger is active, because pg_event_trigger_ddl_commands() calls these functions. The same code paths are also reachable via pg_identify_object() and pg_identify_object_as_address(). This commit adds the missing cases. Test coverage is added in object_address.sql for these two catalog types and in create_property_graph.sql covering all property graph object types. A test in event_trigger.sql verifies that DROP PROPERTY GRAPH works correctly when an event trigger is active. Author: Bertrand Drouvot <[email protected]> Reviewed-by: Michael Paquier <[email protected]> Reviewed-by: Ashutosh Bapat <[email protected]> Discussion: https://postgr.es/m/aej1DkLwhyZWmtxJ@bdtpg --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 78 ++++++++++++++++ src/test/regress/expected/event_trigger.out | 17 ++++ src/test/regress/expected/object_address.out | 10 +- .../regress/sql/create_property_graph.sql | 23 +++++ src/test/regress/sql/event_trigger.sql | 13 +++ src/test/regress/sql/object_address.sql | 6 +- 7 files changed, 238 insertions(+), 2 deletions(-) 14.7% src/backend/catalog/ 75.5% src/test/regress/expected/ 9.7% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..eb9e17fb727 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -752,6 +752,84 @@ SELECT (pg_identify_object(classid, objid, objsubid)).* type | create_property_graph_tests | g2 | create_property_graph_tests.g2 (21 rows) +-- test object address functions with recursive dependency walk +-- covers all property graph object types including indirect dependents +SELECT * +FROM ( + WITH RECURSIVE deps (classid, objid, objsubid, refclassid, refobjid, refobjsubid) AS ( + SELECT classid, objid, objsubid, + refclassid, refobjid, refobjsubid + FROM pg_depend + WHERE refclassid = 'pg_class'::regclass AND + refobjid = 'create_property_graph_tests.gt'::regclass + UNION ALL + SELECT d.classid, d.objid, d.objsubid, + d.refclassid, d.refobjid, d.refobjsubid + FROM pg_depend d + JOIN deps dp ON d.refclassid = dp.classid AND d.refobjid = dp.objid AND d.refobjsubid = dp.objsubid + ) + SELECT pg_describe_object(classid, objid, objsubid) as obj, + pg_identify_object(classid, objid, objsubid) as ident, + pg_identify_object_as_address(classid, objid, objsubid) as addr + FROM deps +) s +ORDER BY obj COLLATE "C", ident::text COLLATE "C"; + obj | ident | addr +----------------------------------------------------------+----------------------------------------------------------------------------+---------------------------------------------------------------------------- + edge e of property graph gt | ("property graph element",,,"e of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,e}",{}) + edge e of property graph gt | ("property graph element",,,"e of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,e}",{}) + edge e of property graph gt | ("property graph element",,,"e of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of property graph gt | ("property graph label",,,"e of create_property_graph_tests.gt") | ("property graph label","{create_property_graph_tests,gt,e}",{}) + label v1 of property graph gt | ("property graph label",,,"v1 of create_property_graph_tests.gt") | ("property graph label","{create_property_graph_tests,gt,v1}",{}) + label v1 of vertex v1 of property graph gt | ("property graph element label",,,"v1 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v1}",{}) + label v1 of vertex v1 of property graph gt | ("property graph element label",,,"v1 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v1}",{}) + label v2 of property graph gt | ("property graph label",,,"v2 of create_property_graph_tests.gt") | ("property graph label","{create_property_graph_tests,gt,v2}",{}) + label v2 of vertex v2 of property graph gt | ("property graph element label",,,"v2 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v2}",{}) + label v2 of vertex v2 of property graph gt | ("property graph element label",,,"v2 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v2}",{}) + property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property a of property graph gt | ("property graph property",,,"a of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,a}",{}) + property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property b of property graph gt | ("property graph property",,,"b of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,b}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of property graph gt | ("property graph property",,,"c of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,c}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of property graph gt | ("property graph property",,,"k1 of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,k1}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of property graph gt | ("property graph property",,,"k2 of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,k2}",{}) + property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property m of property graph gt | ("property graph property",,,"m of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,m}",{}) + property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property n of property graph gt | ("property graph property",,,"n of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,n}",{}) + type gt | (type,create_property_graph_tests,gt,create_property_graph_tests.gt) | (type,{create_property_graph_tests.gt},{}) + type gt[] | (type,create_property_graph_tests,_gt,create_property_graph_tests.gt[]) | (type,{create_property_graph_tests.gt[]},{}) + vertex v1 of property graph gt | ("property graph element",,,"v1 of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,v1}",{}) + vertex v2 of property graph gt | ("property graph element",,,"v2 of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,v2}",{}) +(52 rows) + \a\t SELECT pg_get_propgraphdef('g2'::regclass); CREATE PROPERTY GRAPH create_property_graph_tests.g2 diff --git a/src/test/regress/expected/event_trigger.out b/src/test/regress/expected/event_trigger.out index 065f586310f..ed8d5df397e 100644 --- a/src/test/regress/expected/event_trigger.out +++ b/src/test/regress/expected/event_trigger.out @@ -173,6 +173,23 @@ NOTICE: test_event_trigger: ddl_command_end CREATE USER MAPPING alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; NOTICE: test_event_trigger: ddl_command_end ALTER DEFAULT PRIVILEGES +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE TABLE t2x (i int PRIMARY KEY, j text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); +NOTICE: test_event_trigger: ddl_command_end CREATE PROPERTY GRAPH +DROP PROPERTY GRAPH gx; +NOTICE: test_event_trigger: ddl_command_end DROP PROPERTY GRAPH +DROP TABLE t1x, t2x; +NOTICE: test_event_trigger: ddl_command_end DROP TABLE -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; ERROR: permission denied to change owner of event trigger "regress_event_trigger" diff --git a/src/test/regress/expected/object_address.out b/src/test/regress/expected/object_address.out index 97227d67a54..5e53f0b092e 100644 --- a/src/test/regress/expected/object_address.out +++ b/src/test/regress/expected/object_address.out @@ -67,7 +67,9 @@ DECLARE BEGIN FOR objtype IN VALUES ('toast table'), ('index column'), ('sequence column'), ('toast table column'), ('view column'), ('materialized view column'), - ('property graph element'), ('property graph label'), ('property graph property') + ('property graph element'), ('property graph element label'), + ('property graph label'), ('property graph label property'), + ('property graph property') LOOP BEGIN PERFORM pg_get_object_address(objtype, '{one}', '{}'); @@ -84,7 +86,9 @@ WARNING: error for toast table column: unsupported object type "toast table col WARNING: error for view column: unsupported object type "view column" WARNING: error for materialized view column: unsupported object type "materialized view column" WARNING: error for property graph element: unsupported object type "property graph element" +WARNING: error for property graph element label: unrecognized object type "property graph element label" WARNING: error for property graph label: unsupported object type "property graph label" +WARNING: error for property graph label property: unrecognized object type "property graph label property" WARNING: error for property graph property: unsupported object type "property graph property" -- miscellaneous other errors select * from pg_get_object_address('operator of access method', '{btree,integer_ops,1}', '{int4,bool}'); @@ -593,7 +597,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace @@ -653,6 +659,8 @@ ORDER BY objects.classid, objects.objid, objects.objsubid; ("(""parameter ACL"",,,)")|("(""parameter ACL"",,)")|NULL ("(""property graph element"",,,)")|("(""property graph element"",,)")|NULL ("(""property graph label"",,,)")|("(""property graph label"",,)")|NULL +("(""property graph element label"",,,)")|("(""property graph element label"",,)")|NULL ("(""property graph property"",,,)")|("(""property graph property"",,)")|NULL +("(""property graph label property"",,,)")|("(""property graph label property"",,)")|NULL -- restore normal output mode \a\t diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..9608dd5c4af 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -298,6 +298,29 @@ SELECT (pg_identify_object(classid, objid, objsubid)).* refobjid = 'create_property_graph_tests.g2'::regclass ORDER BY 1, 2, 3, 4; +-- test object address functions with recursive dependency walk +-- covers all property graph object types including indirect dependents +SELECT * +FROM ( + WITH RECURSIVE deps (classid, objid, objsubid, refclassid, refobjid, refobjsubid) AS ( + SELECT classid, objid, objsubid, + refclassid, refobjid, refobjsubid + FROM pg_depend + WHERE refclassid = 'pg_class'::regclass AND + refobjid = 'create_property_graph_tests.gt'::regclass + UNION ALL + SELECT d.classid, d.objid, d.objsubid, + d.refclassid, d.refobjid, d.refobjsubid + FROM pg_depend d + JOIN deps dp ON d.refclassid = dp.classid AND d.refobjid = dp.objid AND d.refobjsubid = dp.objsubid + ) + SELECT pg_describe_object(classid, objid, objsubid) as obj, + pg_identify_object(classid, objid, objsubid) as ident, + pg_identify_object_as_address(classid, objid, objsubid) as addr + FROM deps +) s +ORDER BY obj COLLATE "C", ident::text COLLATE "C"; + \a\t SELECT pg_get_propgraphdef('g2'::regclass); SELECT pg_get_propgraphdef('g3'::regclass); diff --git a/src/test/regress/sql/event_trigger.sql b/src/test/regress/sql/event_trigger.sql index 32e9bb58c5e..271f443378b 100644 --- a/src/test/regress/sql/event_trigger.sql +++ b/src/test/regress/sql/event_trigger.sql @@ -143,6 +143,19 @@ create user mapping for regress_evt_user server useless_server; alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +CREATE TABLE t2x (i int PRIMARY KEY, j text); + +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); + +DROP PROPERTY GRAPH gx; +DROP TABLE t1x, t2x; + -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; diff --git a/src/test/regress/sql/object_address.sql b/src/test/regress/sql/object_address.sql index 1bbe9457c1c..27109d421c7 100644 --- a/src/test/regress/sql/object_address.sql +++ b/src/test/regress/sql/object_address.sql @@ -67,7 +67,9 @@ DECLARE BEGIN FOR objtype IN VALUES ('toast table'), ('index column'), ('sequence column'), ('toast table column'), ('view column'), ('materialized view column'), - ('property graph element'), ('property graph label'), ('property graph property') + ('property graph element'), ('property graph element label'), + ('property graph label'), ('property graph label property'), + ('property graph property') LOOP BEGIN PERFORM pg_get_object_address(objtype, '{one}', '{}'); @@ -282,7 +284,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace -- 2.34.1 --R84XrR4Hgw0dH3Ec-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v2] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-23 09:27 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-23 09:27 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing them to hit the default case and error out with "unsupported object class". During DROP PROPERTY GRAPH, this manifests when an event trigger is active, because pg_event_trigger_ddl_commands() calls these functions. The same code paths are also reachable via pg_identify_object() and pg_identify_object_as_address(). This commit adds the missing cases. Test coverage is added in object_address.sql for these two catalog types via the zero-OID test that exercises pg_identify_object() and pg_identify_object_as_address(). A test in event_trigger.sql verifies that DROP PROPERTY GRAPH works correctly when an event trigger is active. Author: Bertrand Drouvot <[email protected]> Reviewed-by: Michael Paquier <[email protected]> Reviewed-by: Ashutosh Bapat <[email protected]> Discussion: https://postgr.es/m/aej1DkLwhyZWmtxJ@bdtpg --- src/backend/catalog/objectaddress.c | 93 ++++++++++++++++++++ src/test/regress/expected/event_trigger.out | 17 ++++ src/test/regress/expected/object_address.out | 4 + src/test/regress/sql/event_trigger.sql | 13 +++ src/test/regress/sql/object_address.sql | 2 + 5 files changed, 129 insertions(+) 62.4% src/backend/catalog/ 25.6% src/test/regress/expected/ 11.8% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/event_trigger.out b/src/test/regress/expected/event_trigger.out index 065f586310f..ed8d5df397e 100644 --- a/src/test/regress/expected/event_trigger.out +++ b/src/test/regress/expected/event_trigger.out @@ -173,6 +173,23 @@ NOTICE: test_event_trigger: ddl_command_end CREATE USER MAPPING alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; NOTICE: test_event_trigger: ddl_command_end ALTER DEFAULT PRIVILEGES +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE TABLE t2x (i int PRIMARY KEY, j text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); +NOTICE: test_event_trigger: ddl_command_end CREATE PROPERTY GRAPH +DROP PROPERTY GRAPH gx; +NOTICE: test_event_trigger: ddl_command_end DROP PROPERTY GRAPH +DROP TABLE t1x, t2x; +NOTICE: test_event_trigger: ddl_command_end DROP TABLE -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; ERROR: permission denied to change owner of event trigger "regress_event_trigger" diff --git a/src/test/regress/expected/object_address.out b/src/test/regress/expected/object_address.out index 97227d67a54..729c3537f25 100644 --- a/src/test/regress/expected/object_address.out +++ b/src/test/regress/expected/object_address.out @@ -593,7 +593,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace @@ -653,6 +655,8 @@ ORDER BY objects.classid, objects.objid, objects.objsubid; ("(""parameter ACL"",,,)")|("(""parameter ACL"",,)")|NULL ("(""property graph element"",,,)")|("(""property graph element"",,)")|NULL ("(""property graph label"",,,)")|("(""property graph label"",,)")|NULL +("(""property graph element label"",,,)")|("(""property graph element label"",,)")|NULL ("(""property graph property"",,,)")|("(""property graph property"",,)")|NULL +("(""property graph label property"",,,)")|("(""property graph label property"",,)")|NULL -- restore normal output mode \a\t diff --git a/src/test/regress/sql/event_trigger.sql b/src/test/regress/sql/event_trigger.sql index 32e9bb58c5e..271f443378b 100644 --- a/src/test/regress/sql/event_trigger.sql +++ b/src/test/regress/sql/event_trigger.sql @@ -143,6 +143,19 @@ create user mapping for regress_evt_user server useless_server; alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +CREATE TABLE t2x (i int PRIMARY KEY, j text); + +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); + +DROP PROPERTY GRAPH gx; +DROP TABLE t1x, t2x; + -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; diff --git a/src/test/regress/sql/object_address.sql b/src/test/regress/sql/object_address.sql index 1bbe9457c1c..620dacf1045 100644 --- a/src/test/regress/sql/object_address.sql +++ b/src/test/regress/sql/object_address.sql @@ -282,7 +282,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace -- 2.34.1 --gtUR827Uq8d5gVsQ-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v3] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-23 09:27 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-23 09:27 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing them to hit the default case and error out with "unsupported object class". During DROP PROPERTY GRAPH, this manifests when an event trigger is active, because pg_event_trigger_ddl_commands() calls these functions. The same code paths are also reachable via pg_identify_object() and pg_identify_object_as_address(). This commit adds the missing cases. Test coverage is added in object_address.sql for these two catalog types and in create_property_graph.sql covering all property graph object types. A test in event_trigger.sql verifies that DROP PROPERTY GRAPH works correctly when an event trigger is active. Author: Bertrand Drouvot <[email protected]> Reviewed-by: Michael Paquier <[email protected]> Reviewed-by: Ashutosh Bapat <[email protected]> Discussion: https://postgr.es/m/aej1DkLwhyZWmtxJ@bdtpg --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 78 ++++++++++++++++ src/test/regress/expected/event_trigger.out | 17 ++++ src/test/regress/expected/object_address.out | 10 +- .../regress/sql/create_property_graph.sql | 23 +++++ src/test/regress/sql/event_trigger.sql | 13 +++ src/test/regress/sql/object_address.sql | 6 +- 7 files changed, 238 insertions(+), 2 deletions(-) 14.7% src/backend/catalog/ 75.5% src/test/regress/expected/ 9.7% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..eb9e17fb727 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -752,6 +752,84 @@ SELECT (pg_identify_object(classid, objid, objsubid)).* type | create_property_graph_tests | g2 | create_property_graph_tests.g2 (21 rows) +-- test object address functions with recursive dependency walk +-- covers all property graph object types including indirect dependents +SELECT * +FROM ( + WITH RECURSIVE deps (classid, objid, objsubid, refclassid, refobjid, refobjsubid) AS ( + SELECT classid, objid, objsubid, + refclassid, refobjid, refobjsubid + FROM pg_depend + WHERE refclassid = 'pg_class'::regclass AND + refobjid = 'create_property_graph_tests.gt'::regclass + UNION ALL + SELECT d.classid, d.objid, d.objsubid, + d.refclassid, d.refobjid, d.refobjsubid + FROM pg_depend d + JOIN deps dp ON d.refclassid = dp.classid AND d.refobjid = dp.objid AND d.refobjsubid = dp.objsubid + ) + SELECT pg_describe_object(classid, objid, objsubid) as obj, + pg_identify_object(classid, objid, objsubid) as ident, + pg_identify_object_as_address(classid, objid, objsubid) as addr + FROM deps +) s +ORDER BY obj COLLATE "C", ident::text COLLATE "C"; + obj | ident | addr +----------------------------------------------------------+----------------------------------------------------------------------------+---------------------------------------------------------------------------- + edge e of property graph gt | ("property graph element",,,"e of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,e}",{}) + edge e of property graph gt | ("property graph element",,,"e of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,e}",{}) + edge e of property graph gt | ("property graph element",,,"e of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of property graph gt | ("property graph label",,,"e of create_property_graph_tests.gt") | ("property graph label","{create_property_graph_tests,gt,e}",{}) + label v1 of property graph gt | ("property graph label",,,"v1 of create_property_graph_tests.gt") | ("property graph label","{create_property_graph_tests,gt,v1}",{}) + label v1 of vertex v1 of property graph gt | ("property graph element label",,,"v1 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v1}",{}) + label v1 of vertex v1 of property graph gt | ("property graph element label",,,"v1 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v1}",{}) + label v2 of property graph gt | ("property graph label",,,"v2 of create_property_graph_tests.gt") | ("property graph label","{create_property_graph_tests,gt,v2}",{}) + label v2 of vertex v2 of property graph gt | ("property graph element label",,,"v2 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v2}",{}) + label v2 of vertex v2 of property graph gt | ("property graph element label",,,"v2 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v2}",{}) + property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property a of property graph gt | ("property graph property",,,"a of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,a}",{}) + property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property b of property graph gt | ("property graph property",,,"b of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,b}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of property graph gt | ("property graph property",,,"c of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,c}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of property graph gt | ("property graph property",,,"k1 of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,k1}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of property graph gt | ("property graph property",,,"k2 of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,k2}",{}) + property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property m of property graph gt | ("property graph property",,,"m of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,m}",{}) + property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property n of property graph gt | ("property graph property",,,"n of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,n}",{}) + type gt | (type,create_property_graph_tests,gt,create_property_graph_tests.gt) | (type,{create_property_graph_tests.gt},{}) + type gt[] | (type,create_property_graph_tests,_gt,create_property_graph_tests.gt[]) | (type,{create_property_graph_tests.gt[]},{}) + vertex v1 of property graph gt | ("property graph element",,,"v1 of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,v1}",{}) + vertex v2 of property graph gt | ("property graph element",,,"v2 of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,v2}",{}) +(52 rows) + \a\t SELECT pg_get_propgraphdef('g2'::regclass); CREATE PROPERTY GRAPH create_property_graph_tests.g2 diff --git a/src/test/regress/expected/event_trigger.out b/src/test/regress/expected/event_trigger.out index 065f586310f..ed8d5df397e 100644 --- a/src/test/regress/expected/event_trigger.out +++ b/src/test/regress/expected/event_trigger.out @@ -173,6 +173,23 @@ NOTICE: test_event_trigger: ddl_command_end CREATE USER MAPPING alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; NOTICE: test_event_trigger: ddl_command_end ALTER DEFAULT PRIVILEGES +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE TABLE t2x (i int PRIMARY KEY, j text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); +NOTICE: test_event_trigger: ddl_command_end CREATE PROPERTY GRAPH +DROP PROPERTY GRAPH gx; +NOTICE: test_event_trigger: ddl_command_end DROP PROPERTY GRAPH +DROP TABLE t1x, t2x; +NOTICE: test_event_trigger: ddl_command_end DROP TABLE -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; ERROR: permission denied to change owner of event trigger "regress_event_trigger" diff --git a/src/test/regress/expected/object_address.out b/src/test/regress/expected/object_address.out index 97227d67a54..5e53f0b092e 100644 --- a/src/test/regress/expected/object_address.out +++ b/src/test/regress/expected/object_address.out @@ -67,7 +67,9 @@ DECLARE BEGIN FOR objtype IN VALUES ('toast table'), ('index column'), ('sequence column'), ('toast table column'), ('view column'), ('materialized view column'), - ('property graph element'), ('property graph label'), ('property graph property') + ('property graph element'), ('property graph element label'), + ('property graph label'), ('property graph label property'), + ('property graph property') LOOP BEGIN PERFORM pg_get_object_address(objtype, '{one}', '{}'); @@ -84,7 +86,9 @@ WARNING: error for toast table column: unsupported object type "toast table col WARNING: error for view column: unsupported object type "view column" WARNING: error for materialized view column: unsupported object type "materialized view column" WARNING: error for property graph element: unsupported object type "property graph element" +WARNING: error for property graph element label: unrecognized object type "property graph element label" WARNING: error for property graph label: unsupported object type "property graph label" +WARNING: error for property graph label property: unrecognized object type "property graph label property" WARNING: error for property graph property: unsupported object type "property graph property" -- miscellaneous other errors select * from pg_get_object_address('operator of access method', '{btree,integer_ops,1}', '{int4,bool}'); @@ -593,7 +597,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace @@ -653,6 +659,8 @@ ORDER BY objects.classid, objects.objid, objects.objsubid; ("(""parameter ACL"",,,)")|("(""parameter ACL"",,)")|NULL ("(""property graph element"",,,)")|("(""property graph element"",,)")|NULL ("(""property graph label"",,,)")|("(""property graph label"",,)")|NULL +("(""property graph element label"",,,)")|("(""property graph element label"",,)")|NULL ("(""property graph property"",,,)")|("(""property graph property"",,)")|NULL +("(""property graph label property"",,,)")|("(""property graph label property"",,)")|NULL -- restore normal output mode \a\t diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..9608dd5c4af 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -298,6 +298,29 @@ SELECT (pg_identify_object(classid, objid, objsubid)).* refobjid = 'create_property_graph_tests.g2'::regclass ORDER BY 1, 2, 3, 4; +-- test object address functions with recursive dependency walk +-- covers all property graph object types including indirect dependents +SELECT * +FROM ( + WITH RECURSIVE deps (classid, objid, objsubid, refclassid, refobjid, refobjsubid) AS ( + SELECT classid, objid, objsubid, + refclassid, refobjid, refobjsubid + FROM pg_depend + WHERE refclassid = 'pg_class'::regclass AND + refobjid = 'create_property_graph_tests.gt'::regclass + UNION ALL + SELECT d.classid, d.objid, d.objsubid, + d.refclassid, d.refobjid, d.refobjsubid + FROM pg_depend d + JOIN deps dp ON d.refclassid = dp.classid AND d.refobjid = dp.objid AND d.refobjsubid = dp.objsubid + ) + SELECT pg_describe_object(classid, objid, objsubid) as obj, + pg_identify_object(classid, objid, objsubid) as ident, + pg_identify_object_as_address(classid, objid, objsubid) as addr + FROM deps +) s +ORDER BY obj COLLATE "C", ident::text COLLATE "C"; + \a\t SELECT pg_get_propgraphdef('g2'::regclass); SELECT pg_get_propgraphdef('g3'::regclass); diff --git a/src/test/regress/sql/event_trigger.sql b/src/test/regress/sql/event_trigger.sql index 32e9bb58c5e..271f443378b 100644 --- a/src/test/regress/sql/event_trigger.sql +++ b/src/test/regress/sql/event_trigger.sql @@ -143,6 +143,19 @@ create user mapping for regress_evt_user server useless_server; alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +CREATE TABLE t2x (i int PRIMARY KEY, j text); + +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); + +DROP PROPERTY GRAPH gx; +DROP TABLE t1x, t2x; + -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; diff --git a/src/test/regress/sql/object_address.sql b/src/test/regress/sql/object_address.sql index 1bbe9457c1c..27109d421c7 100644 --- a/src/test/regress/sql/object_address.sql +++ b/src/test/regress/sql/object_address.sql @@ -67,7 +67,9 @@ DECLARE BEGIN FOR objtype IN VALUES ('toast table'), ('index column'), ('sequence column'), ('toast table column'), ('view column'), ('materialized view column'), - ('property graph element'), ('property graph label'), ('property graph property') + ('property graph element'), ('property graph element label'), + ('property graph label'), ('property graph label property'), + ('property graph property') LOOP BEGIN PERFORM pg_get_object_address(objtype, '{one}', '{}'); @@ -282,7 +284,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace -- 2.34.1 --R84XrR4Hgw0dH3Ec-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v3] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-23 09:27 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-23 09:27 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing them to hit the default case and error out with "unsupported object class". During DROP PROPERTY GRAPH, this manifests when an event trigger is active, because pg_event_trigger_ddl_commands() calls these functions. The same code paths are also reachable via pg_identify_object() and pg_identify_object_as_address(). This commit adds the missing cases. Test coverage is added in object_address.sql for these two catalog types and in create_property_graph.sql covering all property graph object types. A test in event_trigger.sql verifies that DROP PROPERTY GRAPH works correctly when an event trigger is active. Author: Bertrand Drouvot <[email protected]> Reviewed-by: Michael Paquier <[email protected]> Reviewed-by: Ashutosh Bapat <[email protected]> Discussion: https://postgr.es/m/aej1DkLwhyZWmtxJ@bdtpg --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 78 ++++++++++++++++ src/test/regress/expected/event_trigger.out | 17 ++++ src/test/regress/expected/object_address.out | 10 +- .../regress/sql/create_property_graph.sql | 23 +++++ src/test/regress/sql/event_trigger.sql | 13 +++ src/test/regress/sql/object_address.sql | 6 +- 7 files changed, 238 insertions(+), 2 deletions(-) 14.7% src/backend/catalog/ 75.5% src/test/regress/expected/ 9.7% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..eb9e17fb727 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -752,6 +752,84 @@ SELECT (pg_identify_object(classid, objid, objsubid)).* type | create_property_graph_tests | g2 | create_property_graph_tests.g2 (21 rows) +-- test object address functions with recursive dependency walk +-- covers all property graph object types including indirect dependents +SELECT * +FROM ( + WITH RECURSIVE deps (classid, objid, objsubid, refclassid, refobjid, refobjsubid) AS ( + SELECT classid, objid, objsubid, + refclassid, refobjid, refobjsubid + FROM pg_depend + WHERE refclassid = 'pg_class'::regclass AND + refobjid = 'create_property_graph_tests.gt'::regclass + UNION ALL + SELECT d.classid, d.objid, d.objsubid, + d.refclassid, d.refobjid, d.refobjsubid + FROM pg_depend d + JOIN deps dp ON d.refclassid = dp.classid AND d.refobjid = dp.objid AND d.refobjsubid = dp.objsubid + ) + SELECT pg_describe_object(classid, objid, objsubid) as obj, + pg_identify_object(classid, objid, objsubid) as ident, + pg_identify_object_as_address(classid, objid, objsubid) as addr + FROM deps +) s +ORDER BY obj COLLATE "C", ident::text COLLATE "C"; + obj | ident | addr +----------------------------------------------------------+----------------------------------------------------------------------------+---------------------------------------------------------------------------- + edge e of property graph gt | ("property graph element",,,"e of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,e}",{}) + edge e of property graph gt | ("property graph element",,,"e of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,e}",{}) + edge e of property graph gt | ("property graph element",,,"e of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of property graph gt | ("property graph label",,,"e of create_property_graph_tests.gt") | ("property graph label","{create_property_graph_tests,gt,e}",{}) + label v1 of property graph gt | ("property graph label",,,"v1 of create_property_graph_tests.gt") | ("property graph label","{create_property_graph_tests,gt,v1}",{}) + label v1 of vertex v1 of property graph gt | ("property graph element label",,,"v1 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v1}",{}) + label v1 of vertex v1 of property graph gt | ("property graph element label",,,"v1 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v1}",{}) + label v2 of property graph gt | ("property graph label",,,"v2 of create_property_graph_tests.gt") | ("property graph label","{create_property_graph_tests,gt,v2}",{}) + label v2 of vertex v2 of property graph gt | ("property graph element label",,,"v2 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v2}",{}) + label v2 of vertex v2 of property graph gt | ("property graph element label",,,"v2 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v2}",{}) + property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property a of property graph gt | ("property graph property",,,"a of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,a}",{}) + property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property b of property graph gt | ("property graph property",,,"b of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,b}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of property graph gt | ("property graph property",,,"c of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,c}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of property graph gt | ("property graph property",,,"k1 of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,k1}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of property graph gt | ("property graph property",,,"k2 of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,k2}",{}) + property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property m of property graph gt | ("property graph property",,,"m of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,m}",{}) + property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property n of property graph gt | ("property graph property",,,"n of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,n}",{}) + type gt | (type,create_property_graph_tests,gt,create_property_graph_tests.gt) | (type,{create_property_graph_tests.gt},{}) + type gt[] | (type,create_property_graph_tests,_gt,create_property_graph_tests.gt[]) | (type,{create_property_graph_tests.gt[]},{}) + vertex v1 of property graph gt | ("property graph element",,,"v1 of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,v1}",{}) + vertex v2 of property graph gt | ("property graph element",,,"v2 of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,v2}",{}) +(52 rows) + \a\t SELECT pg_get_propgraphdef('g2'::regclass); CREATE PROPERTY GRAPH create_property_graph_tests.g2 diff --git a/src/test/regress/expected/event_trigger.out b/src/test/regress/expected/event_trigger.out index 065f586310f..ed8d5df397e 100644 --- a/src/test/regress/expected/event_trigger.out +++ b/src/test/regress/expected/event_trigger.out @@ -173,6 +173,23 @@ NOTICE: test_event_trigger: ddl_command_end CREATE USER MAPPING alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; NOTICE: test_event_trigger: ddl_command_end ALTER DEFAULT PRIVILEGES +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE TABLE t2x (i int PRIMARY KEY, j text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); +NOTICE: test_event_trigger: ddl_command_end CREATE PROPERTY GRAPH +DROP PROPERTY GRAPH gx; +NOTICE: test_event_trigger: ddl_command_end DROP PROPERTY GRAPH +DROP TABLE t1x, t2x; +NOTICE: test_event_trigger: ddl_command_end DROP TABLE -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; ERROR: permission denied to change owner of event trigger "regress_event_trigger" diff --git a/src/test/regress/expected/object_address.out b/src/test/regress/expected/object_address.out index 97227d67a54..5e53f0b092e 100644 --- a/src/test/regress/expected/object_address.out +++ b/src/test/regress/expected/object_address.out @@ -67,7 +67,9 @@ DECLARE BEGIN FOR objtype IN VALUES ('toast table'), ('index column'), ('sequence column'), ('toast table column'), ('view column'), ('materialized view column'), - ('property graph element'), ('property graph label'), ('property graph property') + ('property graph element'), ('property graph element label'), + ('property graph label'), ('property graph label property'), + ('property graph property') LOOP BEGIN PERFORM pg_get_object_address(objtype, '{one}', '{}'); @@ -84,7 +86,9 @@ WARNING: error for toast table column: unsupported object type "toast table col WARNING: error for view column: unsupported object type "view column" WARNING: error for materialized view column: unsupported object type "materialized view column" WARNING: error for property graph element: unsupported object type "property graph element" +WARNING: error for property graph element label: unrecognized object type "property graph element label" WARNING: error for property graph label: unsupported object type "property graph label" +WARNING: error for property graph label property: unrecognized object type "property graph label property" WARNING: error for property graph property: unsupported object type "property graph property" -- miscellaneous other errors select * from pg_get_object_address('operator of access method', '{btree,integer_ops,1}', '{int4,bool}'); @@ -593,7 +597,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace @@ -653,6 +659,8 @@ ORDER BY objects.classid, objects.objid, objects.objsubid; ("(""parameter ACL"",,,)")|("(""parameter ACL"",,)")|NULL ("(""property graph element"",,,)")|("(""property graph element"",,)")|NULL ("(""property graph label"",,,)")|("(""property graph label"",,)")|NULL +("(""property graph element label"",,,)")|("(""property graph element label"",,)")|NULL ("(""property graph property"",,,)")|("(""property graph property"",,)")|NULL +("(""property graph label property"",,,)")|("(""property graph label property"",,)")|NULL -- restore normal output mode \a\t diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..9608dd5c4af 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -298,6 +298,29 @@ SELECT (pg_identify_object(classid, objid, objsubid)).* refobjid = 'create_property_graph_tests.g2'::regclass ORDER BY 1, 2, 3, 4; +-- test object address functions with recursive dependency walk +-- covers all property graph object types including indirect dependents +SELECT * +FROM ( + WITH RECURSIVE deps (classid, objid, objsubid, refclassid, refobjid, refobjsubid) AS ( + SELECT classid, objid, objsubid, + refclassid, refobjid, refobjsubid + FROM pg_depend + WHERE refclassid = 'pg_class'::regclass AND + refobjid = 'create_property_graph_tests.gt'::regclass + UNION ALL + SELECT d.classid, d.objid, d.objsubid, + d.refclassid, d.refobjid, d.refobjsubid + FROM pg_depend d + JOIN deps dp ON d.refclassid = dp.classid AND d.refobjid = dp.objid AND d.refobjsubid = dp.objsubid + ) + SELECT pg_describe_object(classid, objid, objsubid) as obj, + pg_identify_object(classid, objid, objsubid) as ident, + pg_identify_object_as_address(classid, objid, objsubid) as addr + FROM deps +) s +ORDER BY obj COLLATE "C", ident::text COLLATE "C"; + \a\t SELECT pg_get_propgraphdef('g2'::regclass); SELECT pg_get_propgraphdef('g3'::regclass); diff --git a/src/test/regress/sql/event_trigger.sql b/src/test/regress/sql/event_trigger.sql index 32e9bb58c5e..271f443378b 100644 --- a/src/test/regress/sql/event_trigger.sql +++ b/src/test/regress/sql/event_trigger.sql @@ -143,6 +143,19 @@ create user mapping for regress_evt_user server useless_server; alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +CREATE TABLE t2x (i int PRIMARY KEY, j text); + +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); + +DROP PROPERTY GRAPH gx; +DROP TABLE t1x, t2x; + -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; diff --git a/src/test/regress/sql/object_address.sql b/src/test/regress/sql/object_address.sql index 1bbe9457c1c..27109d421c7 100644 --- a/src/test/regress/sql/object_address.sql +++ b/src/test/regress/sql/object_address.sql @@ -67,7 +67,9 @@ DECLARE BEGIN FOR objtype IN VALUES ('toast table'), ('index column'), ('sequence column'), ('toast table column'), ('view column'), ('materialized view column'), - ('property graph element'), ('property graph label'), ('property graph property') + ('property graph element'), ('property graph element label'), + ('property graph label'), ('property graph label property'), + ('property graph property') LOOP BEGIN PERFORM pg_get_object_address(objtype, '{one}', '{}'); @@ -282,7 +284,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace -- 2.34.1 --R84XrR4Hgw0dH3Ec-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v2] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-23 09:27 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-23 09:27 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing them to hit the default case and error out with "unsupported object class". During DROP PROPERTY GRAPH, this manifests when an event trigger is active, because pg_event_trigger_ddl_commands() calls these functions. The same code paths are also reachable via pg_identify_object() and pg_identify_object_as_address(). This commit adds the missing cases. Test coverage is added in object_address.sql for these two catalog types via the zero-OID test that exercises pg_identify_object() and pg_identify_object_as_address(). A test in event_trigger.sql verifies that DROP PROPERTY GRAPH works correctly when an event trigger is active. Author: Bertrand Drouvot <[email protected]> Reviewed-by: Michael Paquier <[email protected]> Reviewed-by: Ashutosh Bapat <[email protected]> Discussion: https://postgr.es/m/aej1DkLwhyZWmtxJ@bdtpg --- src/backend/catalog/objectaddress.c | 93 ++++++++++++++++++++ src/test/regress/expected/event_trigger.out | 17 ++++ src/test/regress/expected/object_address.out | 4 + src/test/regress/sql/event_trigger.sql | 13 +++ src/test/regress/sql/object_address.sql | 2 + 5 files changed, 129 insertions(+) 62.4% src/backend/catalog/ 25.6% src/test/regress/expected/ 11.8% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/event_trigger.out b/src/test/regress/expected/event_trigger.out index 065f586310f..ed8d5df397e 100644 --- a/src/test/regress/expected/event_trigger.out +++ b/src/test/regress/expected/event_trigger.out @@ -173,6 +173,23 @@ NOTICE: test_event_trigger: ddl_command_end CREATE USER MAPPING alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; NOTICE: test_event_trigger: ddl_command_end ALTER DEFAULT PRIVILEGES +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE TABLE t2x (i int PRIMARY KEY, j text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); +NOTICE: test_event_trigger: ddl_command_end CREATE PROPERTY GRAPH +DROP PROPERTY GRAPH gx; +NOTICE: test_event_trigger: ddl_command_end DROP PROPERTY GRAPH +DROP TABLE t1x, t2x; +NOTICE: test_event_trigger: ddl_command_end DROP TABLE -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; ERROR: permission denied to change owner of event trigger "regress_event_trigger" diff --git a/src/test/regress/expected/object_address.out b/src/test/regress/expected/object_address.out index 97227d67a54..729c3537f25 100644 --- a/src/test/regress/expected/object_address.out +++ b/src/test/regress/expected/object_address.out @@ -593,7 +593,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace @@ -653,6 +655,8 @@ ORDER BY objects.classid, objects.objid, objects.objsubid; ("(""parameter ACL"",,,)")|("(""parameter ACL"",,)")|NULL ("(""property graph element"",,,)")|("(""property graph element"",,)")|NULL ("(""property graph label"",,,)")|("(""property graph label"",,)")|NULL +("(""property graph element label"",,,)")|("(""property graph element label"",,)")|NULL ("(""property graph property"",,,)")|("(""property graph property"",,)")|NULL +("(""property graph label property"",,,)")|("(""property graph label property"",,)")|NULL -- restore normal output mode \a\t diff --git a/src/test/regress/sql/event_trigger.sql b/src/test/regress/sql/event_trigger.sql index 32e9bb58c5e..271f443378b 100644 --- a/src/test/regress/sql/event_trigger.sql +++ b/src/test/regress/sql/event_trigger.sql @@ -143,6 +143,19 @@ create user mapping for regress_evt_user server useless_server; alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +CREATE TABLE t2x (i int PRIMARY KEY, j text); + +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); + +DROP PROPERTY GRAPH gx; +DROP TABLE t1x, t2x; + -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; diff --git a/src/test/regress/sql/object_address.sql b/src/test/regress/sql/object_address.sql index 1bbe9457c1c..620dacf1045 100644 --- a/src/test/regress/sql/object_address.sql +++ b/src/test/regress/sql/object_address.sql @@ -282,7 +282,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace -- 2.34.1 --gtUR827Uq8d5gVsQ-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v2] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-23 09:27 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-23 09:27 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing them to hit the default case and error out with "unsupported object class". During DROP PROPERTY GRAPH, this manifests when an event trigger is active, because pg_event_trigger_ddl_commands() calls these functions. The same code paths are also reachable via pg_identify_object() and pg_identify_object_as_address(). This commit adds the missing cases. Test coverage is added in object_address.sql for these two catalog types via the zero-OID test that exercises pg_identify_object() and pg_identify_object_as_address(). A test in event_trigger.sql verifies that DROP PROPERTY GRAPH works correctly when an event trigger is active. Author: Bertrand Drouvot <[email protected]> Reviewed-by: Michael Paquier <[email protected]> Reviewed-by: Ashutosh Bapat <[email protected]> Discussion: https://postgr.es/m/aej1DkLwhyZWmtxJ@bdtpg --- src/backend/catalog/objectaddress.c | 93 ++++++++++++++++++++ src/test/regress/expected/event_trigger.out | 17 ++++ src/test/regress/expected/object_address.out | 4 + src/test/regress/sql/event_trigger.sql | 13 +++ src/test/regress/sql/object_address.sql | 2 + 5 files changed, 129 insertions(+) 62.4% src/backend/catalog/ 25.6% src/test/regress/expected/ 11.8% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/event_trigger.out b/src/test/regress/expected/event_trigger.out index 065f586310f..ed8d5df397e 100644 --- a/src/test/regress/expected/event_trigger.out +++ b/src/test/regress/expected/event_trigger.out @@ -173,6 +173,23 @@ NOTICE: test_event_trigger: ddl_command_end CREATE USER MAPPING alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; NOTICE: test_event_trigger: ddl_command_end ALTER DEFAULT PRIVILEGES +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE TABLE t2x (i int PRIMARY KEY, j text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); +NOTICE: test_event_trigger: ddl_command_end CREATE PROPERTY GRAPH +DROP PROPERTY GRAPH gx; +NOTICE: test_event_trigger: ddl_command_end DROP PROPERTY GRAPH +DROP TABLE t1x, t2x; +NOTICE: test_event_trigger: ddl_command_end DROP TABLE -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; ERROR: permission denied to change owner of event trigger "regress_event_trigger" diff --git a/src/test/regress/expected/object_address.out b/src/test/regress/expected/object_address.out index 97227d67a54..729c3537f25 100644 --- a/src/test/regress/expected/object_address.out +++ b/src/test/regress/expected/object_address.out @@ -593,7 +593,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace @@ -653,6 +655,8 @@ ORDER BY objects.classid, objects.objid, objects.objsubid; ("(""parameter ACL"",,,)")|("(""parameter ACL"",,)")|NULL ("(""property graph element"",,,)")|("(""property graph element"",,)")|NULL ("(""property graph label"",,,)")|("(""property graph label"",,)")|NULL +("(""property graph element label"",,,)")|("(""property graph element label"",,)")|NULL ("(""property graph property"",,,)")|("(""property graph property"",,)")|NULL +("(""property graph label property"",,,)")|("(""property graph label property"",,)")|NULL -- restore normal output mode \a\t diff --git a/src/test/regress/sql/event_trigger.sql b/src/test/regress/sql/event_trigger.sql index 32e9bb58c5e..271f443378b 100644 --- a/src/test/regress/sql/event_trigger.sql +++ b/src/test/regress/sql/event_trigger.sql @@ -143,6 +143,19 @@ create user mapping for regress_evt_user server useless_server; alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +CREATE TABLE t2x (i int PRIMARY KEY, j text); + +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); + +DROP PROPERTY GRAPH gx; +DROP TABLE t1x, t2x; + -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; diff --git a/src/test/regress/sql/object_address.sql b/src/test/regress/sql/object_address.sql index 1bbe9457c1c..620dacf1045 100644 --- a/src/test/regress/sql/object_address.sql +++ b/src/test/regress/sql/object_address.sql @@ -282,7 +282,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace -- 2.34.1 --gtUR827Uq8d5gVsQ-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v3] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-23 09:27 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-23 09:27 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing them to hit the default case and error out with "unsupported object class". During DROP PROPERTY GRAPH, this manifests when an event trigger is active, because pg_event_trigger_ddl_commands() calls these functions. The same code paths are also reachable via pg_identify_object() and pg_identify_object_as_address(). This commit adds the missing cases. Test coverage is added in object_address.sql for these two catalog types and in create_property_graph.sql covering all property graph object types. A test in event_trigger.sql verifies that DROP PROPERTY GRAPH works correctly when an event trigger is active. Author: Bertrand Drouvot <[email protected]> Reviewed-by: Michael Paquier <[email protected]> Reviewed-by: Ashutosh Bapat <[email protected]> Discussion: https://postgr.es/m/aej1DkLwhyZWmtxJ@bdtpg --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 78 ++++++++++++++++ src/test/regress/expected/event_trigger.out | 17 ++++ src/test/regress/expected/object_address.out | 10 +- .../regress/sql/create_property_graph.sql | 23 +++++ src/test/regress/sql/event_trigger.sql | 13 +++ src/test/regress/sql/object_address.sql | 6 +- 7 files changed, 238 insertions(+), 2 deletions(-) 14.7% src/backend/catalog/ 75.5% src/test/regress/expected/ 9.7% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..eb9e17fb727 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -752,6 +752,84 @@ SELECT (pg_identify_object(classid, objid, objsubid)).* type | create_property_graph_tests | g2 | create_property_graph_tests.g2 (21 rows) +-- test object address functions with recursive dependency walk +-- covers all property graph object types including indirect dependents +SELECT * +FROM ( + WITH RECURSIVE deps (classid, objid, objsubid, refclassid, refobjid, refobjsubid) AS ( + SELECT classid, objid, objsubid, + refclassid, refobjid, refobjsubid + FROM pg_depend + WHERE refclassid = 'pg_class'::regclass AND + refobjid = 'create_property_graph_tests.gt'::regclass + UNION ALL + SELECT d.classid, d.objid, d.objsubid, + d.refclassid, d.refobjid, d.refobjsubid + FROM pg_depend d + JOIN deps dp ON d.refclassid = dp.classid AND d.refobjid = dp.objid AND d.refobjsubid = dp.objsubid + ) + SELECT pg_describe_object(classid, objid, objsubid) as obj, + pg_identify_object(classid, objid, objsubid) as ident, + pg_identify_object_as_address(classid, objid, objsubid) as addr + FROM deps +) s +ORDER BY obj COLLATE "C", ident::text COLLATE "C"; + obj | ident | addr +----------------------------------------------------------+----------------------------------------------------------------------------+---------------------------------------------------------------------------- + edge e of property graph gt | ("property graph element",,,"e of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,e}",{}) + edge e of property graph gt | ("property graph element",,,"e of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,e}",{}) + edge e of property graph gt | ("property graph element",,,"e of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of property graph gt | ("property graph label",,,"e of create_property_graph_tests.gt") | ("property graph label","{create_property_graph_tests,gt,e}",{}) + label v1 of property graph gt | ("property graph label",,,"v1 of create_property_graph_tests.gt") | ("property graph label","{create_property_graph_tests,gt,v1}",{}) + label v1 of vertex v1 of property graph gt | ("property graph element label",,,"v1 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v1}",{}) + label v1 of vertex v1 of property graph gt | ("property graph element label",,,"v1 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v1}",{}) + label v2 of property graph gt | ("property graph label",,,"v2 of create_property_graph_tests.gt") | ("property graph label","{create_property_graph_tests,gt,v2}",{}) + label v2 of vertex v2 of property graph gt | ("property graph element label",,,"v2 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v2}",{}) + label v2 of vertex v2 of property graph gt | ("property graph element label",,,"v2 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v2}",{}) + property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property a of property graph gt | ("property graph property",,,"a of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,a}",{}) + property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property b of property graph gt | ("property graph property",,,"b of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,b}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of property graph gt | ("property graph property",,,"c of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,c}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of property graph gt | ("property graph property",,,"k1 of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,k1}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of property graph gt | ("property graph property",,,"k2 of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,k2}",{}) + property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property m of property graph gt | ("property graph property",,,"m of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,m}",{}) + property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property n of property graph gt | ("property graph property",,,"n of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,n}",{}) + type gt | (type,create_property_graph_tests,gt,create_property_graph_tests.gt) | (type,{create_property_graph_tests.gt},{}) + type gt[] | (type,create_property_graph_tests,_gt,create_property_graph_tests.gt[]) | (type,{create_property_graph_tests.gt[]},{}) + vertex v1 of property graph gt | ("property graph element",,,"v1 of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,v1}",{}) + vertex v2 of property graph gt | ("property graph element",,,"v2 of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,v2}",{}) +(52 rows) + \a\t SELECT pg_get_propgraphdef('g2'::regclass); CREATE PROPERTY GRAPH create_property_graph_tests.g2 diff --git a/src/test/regress/expected/event_trigger.out b/src/test/regress/expected/event_trigger.out index 065f586310f..ed8d5df397e 100644 --- a/src/test/regress/expected/event_trigger.out +++ b/src/test/regress/expected/event_trigger.out @@ -173,6 +173,23 @@ NOTICE: test_event_trigger: ddl_command_end CREATE USER MAPPING alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; NOTICE: test_event_trigger: ddl_command_end ALTER DEFAULT PRIVILEGES +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE TABLE t2x (i int PRIMARY KEY, j text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); +NOTICE: test_event_trigger: ddl_command_end CREATE PROPERTY GRAPH +DROP PROPERTY GRAPH gx; +NOTICE: test_event_trigger: ddl_command_end DROP PROPERTY GRAPH +DROP TABLE t1x, t2x; +NOTICE: test_event_trigger: ddl_command_end DROP TABLE -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; ERROR: permission denied to change owner of event trigger "regress_event_trigger" diff --git a/src/test/regress/expected/object_address.out b/src/test/regress/expected/object_address.out index 97227d67a54..5e53f0b092e 100644 --- a/src/test/regress/expected/object_address.out +++ b/src/test/regress/expected/object_address.out @@ -67,7 +67,9 @@ DECLARE BEGIN FOR objtype IN VALUES ('toast table'), ('index column'), ('sequence column'), ('toast table column'), ('view column'), ('materialized view column'), - ('property graph element'), ('property graph label'), ('property graph property') + ('property graph element'), ('property graph element label'), + ('property graph label'), ('property graph label property'), + ('property graph property') LOOP BEGIN PERFORM pg_get_object_address(objtype, '{one}', '{}'); @@ -84,7 +86,9 @@ WARNING: error for toast table column: unsupported object type "toast table col WARNING: error for view column: unsupported object type "view column" WARNING: error for materialized view column: unsupported object type "materialized view column" WARNING: error for property graph element: unsupported object type "property graph element" +WARNING: error for property graph element label: unrecognized object type "property graph element label" WARNING: error for property graph label: unsupported object type "property graph label" +WARNING: error for property graph label property: unrecognized object type "property graph label property" WARNING: error for property graph property: unsupported object type "property graph property" -- miscellaneous other errors select * from pg_get_object_address('operator of access method', '{btree,integer_ops,1}', '{int4,bool}'); @@ -593,7 +597,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace @@ -653,6 +659,8 @@ ORDER BY objects.classid, objects.objid, objects.objsubid; ("(""parameter ACL"",,,)")|("(""parameter ACL"",,)")|NULL ("(""property graph element"",,,)")|("(""property graph element"",,)")|NULL ("(""property graph label"",,,)")|("(""property graph label"",,)")|NULL +("(""property graph element label"",,,)")|("(""property graph element label"",,)")|NULL ("(""property graph property"",,,)")|("(""property graph property"",,)")|NULL +("(""property graph label property"",,,)")|("(""property graph label property"",,)")|NULL -- restore normal output mode \a\t diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..9608dd5c4af 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -298,6 +298,29 @@ SELECT (pg_identify_object(classid, objid, objsubid)).* refobjid = 'create_property_graph_tests.g2'::regclass ORDER BY 1, 2, 3, 4; +-- test object address functions with recursive dependency walk +-- covers all property graph object types including indirect dependents +SELECT * +FROM ( + WITH RECURSIVE deps (classid, objid, objsubid, refclassid, refobjid, refobjsubid) AS ( + SELECT classid, objid, objsubid, + refclassid, refobjid, refobjsubid + FROM pg_depend + WHERE refclassid = 'pg_class'::regclass AND + refobjid = 'create_property_graph_tests.gt'::regclass + UNION ALL + SELECT d.classid, d.objid, d.objsubid, + d.refclassid, d.refobjid, d.refobjsubid + FROM pg_depend d + JOIN deps dp ON d.refclassid = dp.classid AND d.refobjid = dp.objid AND d.refobjsubid = dp.objsubid + ) + SELECT pg_describe_object(classid, objid, objsubid) as obj, + pg_identify_object(classid, objid, objsubid) as ident, + pg_identify_object_as_address(classid, objid, objsubid) as addr + FROM deps +) s +ORDER BY obj COLLATE "C", ident::text COLLATE "C"; + \a\t SELECT pg_get_propgraphdef('g2'::regclass); SELECT pg_get_propgraphdef('g3'::regclass); diff --git a/src/test/regress/sql/event_trigger.sql b/src/test/regress/sql/event_trigger.sql index 32e9bb58c5e..271f443378b 100644 --- a/src/test/regress/sql/event_trigger.sql +++ b/src/test/regress/sql/event_trigger.sql @@ -143,6 +143,19 @@ create user mapping for regress_evt_user server useless_server; alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +CREATE TABLE t2x (i int PRIMARY KEY, j text); + +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); + +DROP PROPERTY GRAPH gx; +DROP TABLE t1x, t2x; + -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; diff --git a/src/test/regress/sql/object_address.sql b/src/test/regress/sql/object_address.sql index 1bbe9457c1c..27109d421c7 100644 --- a/src/test/regress/sql/object_address.sql +++ b/src/test/regress/sql/object_address.sql @@ -67,7 +67,9 @@ DECLARE BEGIN FOR objtype IN VALUES ('toast table'), ('index column'), ('sequence column'), ('toast table column'), ('view column'), ('materialized view column'), - ('property graph element'), ('property graph label'), ('property graph property') + ('property graph element'), ('property graph element label'), + ('property graph label'), ('property graph label property'), + ('property graph property') LOOP BEGIN PERFORM pg_get_object_address(objtype, '{one}', '{}'); @@ -282,7 +284,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace -- 2.34.1 --R84XrR4Hgw0dH3Ec-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v2] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-23 09:27 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-23 09:27 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing them to hit the default case and error out with "unsupported object class". During DROP PROPERTY GRAPH, this manifests when an event trigger is active, because pg_event_trigger_ddl_commands() calls these functions. The same code paths are also reachable via pg_identify_object() and pg_identify_object_as_address(). This commit adds the missing cases. Test coverage is added in object_address.sql for these two catalog types via the zero-OID test that exercises pg_identify_object() and pg_identify_object_as_address(). A test in event_trigger.sql verifies that DROP PROPERTY GRAPH works correctly when an event trigger is active. Author: Bertrand Drouvot <[email protected]> Reviewed-by: Michael Paquier <[email protected]> Reviewed-by: Ashutosh Bapat <[email protected]> Discussion: https://postgr.es/m/aej1DkLwhyZWmtxJ@bdtpg --- src/backend/catalog/objectaddress.c | 93 ++++++++++++++++++++ src/test/regress/expected/event_trigger.out | 17 ++++ src/test/regress/expected/object_address.out | 4 + src/test/regress/sql/event_trigger.sql | 13 +++ src/test/regress/sql/object_address.sql | 2 + 5 files changed, 129 insertions(+) 62.4% src/backend/catalog/ 25.6% src/test/regress/expected/ 11.8% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/event_trigger.out b/src/test/regress/expected/event_trigger.out index 065f586310f..ed8d5df397e 100644 --- a/src/test/regress/expected/event_trigger.out +++ b/src/test/regress/expected/event_trigger.out @@ -173,6 +173,23 @@ NOTICE: test_event_trigger: ddl_command_end CREATE USER MAPPING alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; NOTICE: test_event_trigger: ddl_command_end ALTER DEFAULT PRIVILEGES +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE TABLE t2x (i int PRIMARY KEY, j text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); +NOTICE: test_event_trigger: ddl_command_end CREATE PROPERTY GRAPH +DROP PROPERTY GRAPH gx; +NOTICE: test_event_trigger: ddl_command_end DROP PROPERTY GRAPH +DROP TABLE t1x, t2x; +NOTICE: test_event_trigger: ddl_command_end DROP TABLE -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; ERROR: permission denied to change owner of event trigger "regress_event_trigger" diff --git a/src/test/regress/expected/object_address.out b/src/test/regress/expected/object_address.out index 97227d67a54..729c3537f25 100644 --- a/src/test/regress/expected/object_address.out +++ b/src/test/regress/expected/object_address.out @@ -593,7 +593,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace @@ -653,6 +655,8 @@ ORDER BY objects.classid, objects.objid, objects.objsubid; ("(""parameter ACL"",,,)")|("(""parameter ACL"",,)")|NULL ("(""property graph element"",,,)")|("(""property graph element"",,)")|NULL ("(""property graph label"",,,)")|("(""property graph label"",,)")|NULL +("(""property graph element label"",,,)")|("(""property graph element label"",,)")|NULL ("(""property graph property"",,,)")|("(""property graph property"",,)")|NULL +("(""property graph label property"",,,)")|("(""property graph label property"",,)")|NULL -- restore normal output mode \a\t diff --git a/src/test/regress/sql/event_trigger.sql b/src/test/regress/sql/event_trigger.sql index 32e9bb58c5e..271f443378b 100644 --- a/src/test/regress/sql/event_trigger.sql +++ b/src/test/regress/sql/event_trigger.sql @@ -143,6 +143,19 @@ create user mapping for regress_evt_user server useless_server; alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +CREATE TABLE t2x (i int PRIMARY KEY, j text); + +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); + +DROP PROPERTY GRAPH gx; +DROP TABLE t1x, t2x; + -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; diff --git a/src/test/regress/sql/object_address.sql b/src/test/regress/sql/object_address.sql index 1bbe9457c1c..620dacf1045 100644 --- a/src/test/regress/sql/object_address.sql +++ b/src/test/regress/sql/object_address.sql @@ -282,7 +282,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace -- 2.34.1 --gtUR827Uq8d5gVsQ-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v3] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-23 09:27 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-23 09:27 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing them to hit the default case and error out with "unsupported object class". During DROP PROPERTY GRAPH, this manifests when an event trigger is active, because pg_event_trigger_ddl_commands() calls these functions. The same code paths are also reachable via pg_identify_object() and pg_identify_object_as_address(). This commit adds the missing cases. Test coverage is added in object_address.sql for these two catalog types and in create_property_graph.sql covering all property graph object types. A test in event_trigger.sql verifies that DROP PROPERTY GRAPH works correctly when an event trigger is active. Author: Bertrand Drouvot <[email protected]> Reviewed-by: Michael Paquier <[email protected]> Reviewed-by: Ashutosh Bapat <[email protected]> Discussion: https://postgr.es/m/aej1DkLwhyZWmtxJ@bdtpg --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 78 ++++++++++++++++ src/test/regress/expected/event_trigger.out | 17 ++++ src/test/regress/expected/object_address.out | 10 +- .../regress/sql/create_property_graph.sql | 23 +++++ src/test/regress/sql/event_trigger.sql | 13 +++ src/test/regress/sql/object_address.sql | 6 +- 7 files changed, 238 insertions(+), 2 deletions(-) 14.7% src/backend/catalog/ 75.5% src/test/regress/expected/ 9.7% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..eb9e17fb727 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -752,6 +752,84 @@ SELECT (pg_identify_object(classid, objid, objsubid)).* type | create_property_graph_tests | g2 | create_property_graph_tests.g2 (21 rows) +-- test object address functions with recursive dependency walk +-- covers all property graph object types including indirect dependents +SELECT * +FROM ( + WITH RECURSIVE deps (classid, objid, objsubid, refclassid, refobjid, refobjsubid) AS ( + SELECT classid, objid, objsubid, + refclassid, refobjid, refobjsubid + FROM pg_depend + WHERE refclassid = 'pg_class'::regclass AND + refobjid = 'create_property_graph_tests.gt'::regclass + UNION ALL + SELECT d.classid, d.objid, d.objsubid, + d.refclassid, d.refobjid, d.refobjsubid + FROM pg_depend d + JOIN deps dp ON d.refclassid = dp.classid AND d.refobjid = dp.objid AND d.refobjsubid = dp.objsubid + ) + SELECT pg_describe_object(classid, objid, objsubid) as obj, + pg_identify_object(classid, objid, objsubid) as ident, + pg_identify_object_as_address(classid, objid, objsubid) as addr + FROM deps +) s +ORDER BY obj COLLATE "C", ident::text COLLATE "C"; + obj | ident | addr +----------------------------------------------------------+----------------------------------------------------------------------------+---------------------------------------------------------------------------- + edge e of property graph gt | ("property graph element",,,"e of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,e}",{}) + edge e of property graph gt | ("property graph element",,,"e of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,e}",{}) + edge e of property graph gt | ("property graph element",,,"e of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of property graph gt | ("property graph label",,,"e of create_property_graph_tests.gt") | ("property graph label","{create_property_graph_tests,gt,e}",{}) + label v1 of property graph gt | ("property graph label",,,"v1 of create_property_graph_tests.gt") | ("property graph label","{create_property_graph_tests,gt,v1}",{}) + label v1 of vertex v1 of property graph gt | ("property graph element label",,,"v1 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v1}",{}) + label v1 of vertex v1 of property graph gt | ("property graph element label",,,"v1 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v1}",{}) + label v2 of property graph gt | ("property graph label",,,"v2 of create_property_graph_tests.gt") | ("property graph label","{create_property_graph_tests,gt,v2}",{}) + label v2 of vertex v2 of property graph gt | ("property graph element label",,,"v2 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v2}",{}) + label v2 of vertex v2 of property graph gt | ("property graph element label",,,"v2 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v2}",{}) + property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property a of property graph gt | ("property graph property",,,"a of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,a}",{}) + property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property b of property graph gt | ("property graph property",,,"b of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,b}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of property graph gt | ("property graph property",,,"c of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,c}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of property graph gt | ("property graph property",,,"k1 of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,k1}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of property graph gt | ("property graph property",,,"k2 of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,k2}",{}) + property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property m of property graph gt | ("property graph property",,,"m of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,m}",{}) + property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property n of property graph gt | ("property graph property",,,"n of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,n}",{}) + type gt | (type,create_property_graph_tests,gt,create_property_graph_tests.gt) | (type,{create_property_graph_tests.gt},{}) + type gt[] | (type,create_property_graph_tests,_gt,create_property_graph_tests.gt[]) | (type,{create_property_graph_tests.gt[]},{}) + vertex v1 of property graph gt | ("property graph element",,,"v1 of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,v1}",{}) + vertex v2 of property graph gt | ("property graph element",,,"v2 of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,v2}",{}) +(52 rows) + \a\t SELECT pg_get_propgraphdef('g2'::regclass); CREATE PROPERTY GRAPH create_property_graph_tests.g2 diff --git a/src/test/regress/expected/event_trigger.out b/src/test/regress/expected/event_trigger.out index 065f586310f..ed8d5df397e 100644 --- a/src/test/regress/expected/event_trigger.out +++ b/src/test/regress/expected/event_trigger.out @@ -173,6 +173,23 @@ NOTICE: test_event_trigger: ddl_command_end CREATE USER MAPPING alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; NOTICE: test_event_trigger: ddl_command_end ALTER DEFAULT PRIVILEGES +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE TABLE t2x (i int PRIMARY KEY, j text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); +NOTICE: test_event_trigger: ddl_command_end CREATE PROPERTY GRAPH +DROP PROPERTY GRAPH gx; +NOTICE: test_event_trigger: ddl_command_end DROP PROPERTY GRAPH +DROP TABLE t1x, t2x; +NOTICE: test_event_trigger: ddl_command_end DROP TABLE -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; ERROR: permission denied to change owner of event trigger "regress_event_trigger" diff --git a/src/test/regress/expected/object_address.out b/src/test/regress/expected/object_address.out index 97227d67a54..5e53f0b092e 100644 --- a/src/test/regress/expected/object_address.out +++ b/src/test/regress/expected/object_address.out @@ -67,7 +67,9 @@ DECLARE BEGIN FOR objtype IN VALUES ('toast table'), ('index column'), ('sequence column'), ('toast table column'), ('view column'), ('materialized view column'), - ('property graph element'), ('property graph label'), ('property graph property') + ('property graph element'), ('property graph element label'), + ('property graph label'), ('property graph label property'), + ('property graph property') LOOP BEGIN PERFORM pg_get_object_address(objtype, '{one}', '{}'); @@ -84,7 +86,9 @@ WARNING: error for toast table column: unsupported object type "toast table col WARNING: error for view column: unsupported object type "view column" WARNING: error for materialized view column: unsupported object type "materialized view column" WARNING: error for property graph element: unsupported object type "property graph element" +WARNING: error for property graph element label: unrecognized object type "property graph element label" WARNING: error for property graph label: unsupported object type "property graph label" +WARNING: error for property graph label property: unrecognized object type "property graph label property" WARNING: error for property graph property: unsupported object type "property graph property" -- miscellaneous other errors select * from pg_get_object_address('operator of access method', '{btree,integer_ops,1}', '{int4,bool}'); @@ -593,7 +597,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace @@ -653,6 +659,8 @@ ORDER BY objects.classid, objects.objid, objects.objsubid; ("(""parameter ACL"",,,)")|("(""parameter ACL"",,)")|NULL ("(""property graph element"",,,)")|("(""property graph element"",,)")|NULL ("(""property graph label"",,,)")|("(""property graph label"",,)")|NULL +("(""property graph element label"",,,)")|("(""property graph element label"",,)")|NULL ("(""property graph property"",,,)")|("(""property graph property"",,)")|NULL +("(""property graph label property"",,,)")|("(""property graph label property"",,)")|NULL -- restore normal output mode \a\t diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..9608dd5c4af 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -298,6 +298,29 @@ SELECT (pg_identify_object(classid, objid, objsubid)).* refobjid = 'create_property_graph_tests.g2'::regclass ORDER BY 1, 2, 3, 4; +-- test object address functions with recursive dependency walk +-- covers all property graph object types including indirect dependents +SELECT * +FROM ( + WITH RECURSIVE deps (classid, objid, objsubid, refclassid, refobjid, refobjsubid) AS ( + SELECT classid, objid, objsubid, + refclassid, refobjid, refobjsubid + FROM pg_depend + WHERE refclassid = 'pg_class'::regclass AND + refobjid = 'create_property_graph_tests.gt'::regclass + UNION ALL + SELECT d.classid, d.objid, d.objsubid, + d.refclassid, d.refobjid, d.refobjsubid + FROM pg_depend d + JOIN deps dp ON d.refclassid = dp.classid AND d.refobjid = dp.objid AND d.refobjsubid = dp.objsubid + ) + SELECT pg_describe_object(classid, objid, objsubid) as obj, + pg_identify_object(classid, objid, objsubid) as ident, + pg_identify_object_as_address(classid, objid, objsubid) as addr + FROM deps +) s +ORDER BY obj COLLATE "C", ident::text COLLATE "C"; + \a\t SELECT pg_get_propgraphdef('g2'::regclass); SELECT pg_get_propgraphdef('g3'::regclass); diff --git a/src/test/regress/sql/event_trigger.sql b/src/test/regress/sql/event_trigger.sql index 32e9bb58c5e..271f443378b 100644 --- a/src/test/regress/sql/event_trigger.sql +++ b/src/test/regress/sql/event_trigger.sql @@ -143,6 +143,19 @@ create user mapping for regress_evt_user server useless_server; alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +CREATE TABLE t2x (i int PRIMARY KEY, j text); + +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); + +DROP PROPERTY GRAPH gx; +DROP TABLE t1x, t2x; + -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; diff --git a/src/test/regress/sql/object_address.sql b/src/test/regress/sql/object_address.sql index 1bbe9457c1c..27109d421c7 100644 --- a/src/test/regress/sql/object_address.sql +++ b/src/test/regress/sql/object_address.sql @@ -67,7 +67,9 @@ DECLARE BEGIN FOR objtype IN VALUES ('toast table'), ('index column'), ('sequence column'), ('toast table column'), ('view column'), ('materialized view column'), - ('property graph element'), ('property graph label'), ('property graph property') + ('property graph element'), ('property graph element label'), + ('property graph label'), ('property graph label property'), + ('property graph property') LOOP BEGIN PERFORM pg_get_object_address(objtype, '{one}', '{}'); @@ -282,7 +284,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace -- 2.34.1 --R84XrR4Hgw0dH3Ec-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v2] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-23 09:27 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-23 09:27 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing them to hit the default case and error out with "unsupported object class". During DROP PROPERTY GRAPH, this manifests when an event trigger is active, because pg_event_trigger_ddl_commands() calls these functions. The same code paths are also reachable via pg_identify_object() and pg_identify_object_as_address(). This commit adds the missing cases. Test coverage is added in object_address.sql for these two catalog types via the zero-OID test that exercises pg_identify_object() and pg_identify_object_as_address(). A test in event_trigger.sql verifies that DROP PROPERTY GRAPH works correctly when an event trigger is active. Author: Bertrand Drouvot <[email protected]> Reviewed-by: Michael Paquier <[email protected]> Reviewed-by: Ashutosh Bapat <[email protected]> Discussion: https://postgr.es/m/aej1DkLwhyZWmtxJ@bdtpg --- src/backend/catalog/objectaddress.c | 93 ++++++++++++++++++++ src/test/regress/expected/event_trigger.out | 17 ++++ src/test/regress/expected/object_address.out | 4 + src/test/regress/sql/event_trigger.sql | 13 +++ src/test/regress/sql/object_address.sql | 2 + 5 files changed, 129 insertions(+) 62.4% src/backend/catalog/ 25.6% src/test/regress/expected/ 11.8% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/event_trigger.out b/src/test/regress/expected/event_trigger.out index 065f586310f..ed8d5df397e 100644 --- a/src/test/regress/expected/event_trigger.out +++ b/src/test/regress/expected/event_trigger.out @@ -173,6 +173,23 @@ NOTICE: test_event_trigger: ddl_command_end CREATE USER MAPPING alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; NOTICE: test_event_trigger: ddl_command_end ALTER DEFAULT PRIVILEGES +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE TABLE t2x (i int PRIMARY KEY, j text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); +NOTICE: test_event_trigger: ddl_command_end CREATE PROPERTY GRAPH +DROP PROPERTY GRAPH gx; +NOTICE: test_event_trigger: ddl_command_end DROP PROPERTY GRAPH +DROP TABLE t1x, t2x; +NOTICE: test_event_trigger: ddl_command_end DROP TABLE -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; ERROR: permission denied to change owner of event trigger "regress_event_trigger" diff --git a/src/test/regress/expected/object_address.out b/src/test/regress/expected/object_address.out index 97227d67a54..729c3537f25 100644 --- a/src/test/regress/expected/object_address.out +++ b/src/test/regress/expected/object_address.out @@ -593,7 +593,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace @@ -653,6 +655,8 @@ ORDER BY objects.classid, objects.objid, objects.objsubid; ("(""parameter ACL"",,,)")|("(""parameter ACL"",,)")|NULL ("(""property graph element"",,,)")|("(""property graph element"",,)")|NULL ("(""property graph label"",,,)")|("(""property graph label"",,)")|NULL +("(""property graph element label"",,,)")|("(""property graph element label"",,)")|NULL ("(""property graph property"",,,)")|("(""property graph property"",,)")|NULL +("(""property graph label property"",,,)")|("(""property graph label property"",,)")|NULL -- restore normal output mode \a\t diff --git a/src/test/regress/sql/event_trigger.sql b/src/test/regress/sql/event_trigger.sql index 32e9bb58c5e..271f443378b 100644 --- a/src/test/regress/sql/event_trigger.sql +++ b/src/test/regress/sql/event_trigger.sql @@ -143,6 +143,19 @@ create user mapping for regress_evt_user server useless_server; alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +CREATE TABLE t2x (i int PRIMARY KEY, j text); + +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); + +DROP PROPERTY GRAPH gx; +DROP TABLE t1x, t2x; + -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; diff --git a/src/test/regress/sql/object_address.sql b/src/test/regress/sql/object_address.sql index 1bbe9457c1c..620dacf1045 100644 --- a/src/test/regress/sql/object_address.sql +++ b/src/test/regress/sql/object_address.sql @@ -282,7 +282,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace -- 2.34.1 --gtUR827Uq8d5gVsQ-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v2] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-23 09:27 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-23 09:27 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing them to hit the default case and error out with "unsupported object class". During DROP PROPERTY GRAPH, this manifests when an event trigger is active, because pg_event_trigger_ddl_commands() calls these functions. The same code paths are also reachable via pg_identify_object() and pg_identify_object_as_address(). This commit adds the missing cases. Test coverage is added in object_address.sql for these two catalog types via the zero-OID test that exercises pg_identify_object() and pg_identify_object_as_address(). A test in event_trigger.sql verifies that DROP PROPERTY GRAPH works correctly when an event trigger is active. Author: Bertrand Drouvot <[email protected]> Reviewed-by: Michael Paquier <[email protected]> Reviewed-by: Ashutosh Bapat <[email protected]> Discussion: https://postgr.es/m/aej1DkLwhyZWmtxJ@bdtpg --- src/backend/catalog/objectaddress.c | 93 ++++++++++++++++++++ src/test/regress/expected/event_trigger.out | 17 ++++ src/test/regress/expected/object_address.out | 4 + src/test/regress/sql/event_trigger.sql | 13 +++ src/test/regress/sql/object_address.sql | 2 + 5 files changed, 129 insertions(+) 62.4% src/backend/catalog/ 25.6% src/test/regress/expected/ 11.8% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/event_trigger.out b/src/test/regress/expected/event_trigger.out index 065f586310f..ed8d5df397e 100644 --- a/src/test/regress/expected/event_trigger.out +++ b/src/test/regress/expected/event_trigger.out @@ -173,6 +173,23 @@ NOTICE: test_event_trigger: ddl_command_end CREATE USER MAPPING alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; NOTICE: test_event_trigger: ddl_command_end ALTER DEFAULT PRIVILEGES +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE TABLE t2x (i int PRIMARY KEY, j text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); +NOTICE: test_event_trigger: ddl_command_end CREATE PROPERTY GRAPH +DROP PROPERTY GRAPH gx; +NOTICE: test_event_trigger: ddl_command_end DROP PROPERTY GRAPH +DROP TABLE t1x, t2x; +NOTICE: test_event_trigger: ddl_command_end DROP TABLE -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; ERROR: permission denied to change owner of event trigger "regress_event_trigger" diff --git a/src/test/regress/expected/object_address.out b/src/test/regress/expected/object_address.out index 97227d67a54..729c3537f25 100644 --- a/src/test/regress/expected/object_address.out +++ b/src/test/regress/expected/object_address.out @@ -593,7 +593,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace @@ -653,6 +655,8 @@ ORDER BY objects.classid, objects.objid, objects.objsubid; ("(""parameter ACL"",,,)")|("(""parameter ACL"",,)")|NULL ("(""property graph element"",,,)")|("(""property graph element"",,)")|NULL ("(""property graph label"",,,)")|("(""property graph label"",,)")|NULL +("(""property graph element label"",,,)")|("(""property graph element label"",,)")|NULL ("(""property graph property"",,,)")|("(""property graph property"",,)")|NULL +("(""property graph label property"",,,)")|("(""property graph label property"",,)")|NULL -- restore normal output mode \a\t diff --git a/src/test/regress/sql/event_trigger.sql b/src/test/regress/sql/event_trigger.sql index 32e9bb58c5e..271f443378b 100644 --- a/src/test/regress/sql/event_trigger.sql +++ b/src/test/regress/sql/event_trigger.sql @@ -143,6 +143,19 @@ create user mapping for regress_evt_user server useless_server; alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +CREATE TABLE t2x (i int PRIMARY KEY, j text); + +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); + +DROP PROPERTY GRAPH gx; +DROP TABLE t1x, t2x; + -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; diff --git a/src/test/regress/sql/object_address.sql b/src/test/regress/sql/object_address.sql index 1bbe9457c1c..620dacf1045 100644 --- a/src/test/regress/sql/object_address.sql +++ b/src/test/regress/sql/object_address.sql @@ -282,7 +282,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace -- 2.34.1 --gtUR827Uq8d5gVsQ-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v2] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-23 09:27 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-23 09:27 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing them to hit the default case and error out with "unsupported object class". During DROP PROPERTY GRAPH, this manifests when an event trigger is active, because pg_event_trigger_ddl_commands() calls these functions. The same code paths are also reachable via pg_identify_object() and pg_identify_object_as_address(). This commit adds the missing cases. Test coverage is added in object_address.sql for these two catalog types via the zero-OID test that exercises pg_identify_object() and pg_identify_object_as_address(). A test in event_trigger.sql verifies that DROP PROPERTY GRAPH works correctly when an event trigger is active. Author: Bertrand Drouvot <[email protected]> Reviewed-by: Michael Paquier <[email protected]> Reviewed-by: Ashutosh Bapat <[email protected]> Discussion: https://postgr.es/m/aej1DkLwhyZWmtxJ@bdtpg --- src/backend/catalog/objectaddress.c | 93 ++++++++++++++++++++ src/test/regress/expected/event_trigger.out | 17 ++++ src/test/regress/expected/object_address.out | 4 + src/test/regress/sql/event_trigger.sql | 13 +++ src/test/regress/sql/object_address.sql | 2 + 5 files changed, 129 insertions(+) 62.4% src/backend/catalog/ 25.6% src/test/regress/expected/ 11.8% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/event_trigger.out b/src/test/regress/expected/event_trigger.out index 065f586310f..ed8d5df397e 100644 --- a/src/test/regress/expected/event_trigger.out +++ b/src/test/regress/expected/event_trigger.out @@ -173,6 +173,23 @@ NOTICE: test_event_trigger: ddl_command_end CREATE USER MAPPING alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; NOTICE: test_event_trigger: ddl_command_end ALTER DEFAULT PRIVILEGES +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE TABLE t2x (i int PRIMARY KEY, j text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); +NOTICE: test_event_trigger: ddl_command_end CREATE PROPERTY GRAPH +DROP PROPERTY GRAPH gx; +NOTICE: test_event_trigger: ddl_command_end DROP PROPERTY GRAPH +DROP TABLE t1x, t2x; +NOTICE: test_event_trigger: ddl_command_end DROP TABLE -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; ERROR: permission denied to change owner of event trigger "regress_event_trigger" diff --git a/src/test/regress/expected/object_address.out b/src/test/regress/expected/object_address.out index 97227d67a54..729c3537f25 100644 --- a/src/test/regress/expected/object_address.out +++ b/src/test/regress/expected/object_address.out @@ -593,7 +593,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace @@ -653,6 +655,8 @@ ORDER BY objects.classid, objects.objid, objects.objsubid; ("(""parameter ACL"",,,)")|("(""parameter ACL"",,)")|NULL ("(""property graph element"",,,)")|("(""property graph element"",,)")|NULL ("(""property graph label"",,,)")|("(""property graph label"",,)")|NULL +("(""property graph element label"",,,)")|("(""property graph element label"",,)")|NULL ("(""property graph property"",,,)")|("(""property graph property"",,)")|NULL +("(""property graph label property"",,,)")|("(""property graph label property"",,)")|NULL -- restore normal output mode \a\t diff --git a/src/test/regress/sql/event_trigger.sql b/src/test/regress/sql/event_trigger.sql index 32e9bb58c5e..271f443378b 100644 --- a/src/test/regress/sql/event_trigger.sql +++ b/src/test/regress/sql/event_trigger.sql @@ -143,6 +143,19 @@ create user mapping for regress_evt_user server useless_server; alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +CREATE TABLE t2x (i int PRIMARY KEY, j text); + +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); + +DROP PROPERTY GRAPH gx; +DROP TABLE t1x, t2x; + -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; diff --git a/src/test/regress/sql/object_address.sql b/src/test/regress/sql/object_address.sql index 1bbe9457c1c..620dacf1045 100644 --- a/src/test/regress/sql/object_address.sql +++ b/src/test/regress/sql/object_address.sql @@ -282,7 +282,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace -- 2.34.1 --gtUR827Uq8d5gVsQ-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v3] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-23 09:27 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-23 09:27 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing them to hit the default case and error out with "unsupported object class". During DROP PROPERTY GRAPH, this manifests when an event trigger is active, because pg_event_trigger_ddl_commands() calls these functions. The same code paths are also reachable via pg_identify_object() and pg_identify_object_as_address(). This commit adds the missing cases. Test coverage is added in object_address.sql for these two catalog types and in create_property_graph.sql covering all property graph object types. A test in event_trigger.sql verifies that DROP PROPERTY GRAPH works correctly when an event trigger is active. Author: Bertrand Drouvot <[email protected]> Reviewed-by: Michael Paquier <[email protected]> Reviewed-by: Ashutosh Bapat <[email protected]> Discussion: https://postgr.es/m/aej1DkLwhyZWmtxJ@bdtpg --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 78 ++++++++++++++++ src/test/regress/expected/event_trigger.out | 17 ++++ src/test/regress/expected/object_address.out | 10 +- .../regress/sql/create_property_graph.sql | 23 +++++ src/test/regress/sql/event_trigger.sql | 13 +++ src/test/regress/sql/object_address.sql | 6 +- 7 files changed, 238 insertions(+), 2 deletions(-) 14.7% src/backend/catalog/ 75.5% src/test/regress/expected/ 9.7% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..eb9e17fb727 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -752,6 +752,84 @@ SELECT (pg_identify_object(classid, objid, objsubid)).* type | create_property_graph_tests | g2 | create_property_graph_tests.g2 (21 rows) +-- test object address functions with recursive dependency walk +-- covers all property graph object types including indirect dependents +SELECT * +FROM ( + WITH RECURSIVE deps (classid, objid, objsubid, refclassid, refobjid, refobjsubid) AS ( + SELECT classid, objid, objsubid, + refclassid, refobjid, refobjsubid + FROM pg_depend + WHERE refclassid = 'pg_class'::regclass AND + refobjid = 'create_property_graph_tests.gt'::regclass + UNION ALL + SELECT d.classid, d.objid, d.objsubid, + d.refclassid, d.refobjid, d.refobjsubid + FROM pg_depend d + JOIN deps dp ON d.refclassid = dp.classid AND d.refobjid = dp.objid AND d.refobjsubid = dp.objsubid + ) + SELECT pg_describe_object(classid, objid, objsubid) as obj, + pg_identify_object(classid, objid, objsubid) as ident, + pg_identify_object_as_address(classid, objid, objsubid) as addr + FROM deps +) s +ORDER BY obj COLLATE "C", ident::text COLLATE "C"; + obj | ident | addr +----------------------------------------------------------+----------------------------------------------------------------------------+---------------------------------------------------------------------------- + edge e of property graph gt | ("property graph element",,,"e of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,e}",{}) + edge e of property graph gt | ("property graph element",,,"e of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,e}",{}) + edge e of property graph gt | ("property graph element",,,"e of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of property graph gt | ("property graph label",,,"e of create_property_graph_tests.gt") | ("property graph label","{create_property_graph_tests,gt,e}",{}) + label v1 of property graph gt | ("property graph label",,,"v1 of create_property_graph_tests.gt") | ("property graph label","{create_property_graph_tests,gt,v1}",{}) + label v1 of vertex v1 of property graph gt | ("property graph element label",,,"v1 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v1}",{}) + label v1 of vertex v1 of property graph gt | ("property graph element label",,,"v1 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v1}",{}) + label v2 of property graph gt | ("property graph label",,,"v2 of create_property_graph_tests.gt") | ("property graph label","{create_property_graph_tests,gt,v2}",{}) + label v2 of vertex v2 of property graph gt | ("property graph element label",,,"v2 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v2}",{}) + label v2 of vertex v2 of property graph gt | ("property graph element label",,,"v2 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v2}",{}) + property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property a of property graph gt | ("property graph property",,,"a of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,a}",{}) + property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property b of property graph gt | ("property graph property",,,"b of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,b}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of property graph gt | ("property graph property",,,"c of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,c}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of property graph gt | ("property graph property",,,"k1 of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,k1}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of property graph gt | ("property graph property",,,"k2 of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,k2}",{}) + property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property m of property graph gt | ("property graph property",,,"m of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,m}",{}) + property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property n of property graph gt | ("property graph property",,,"n of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,n}",{}) + type gt | (type,create_property_graph_tests,gt,create_property_graph_tests.gt) | (type,{create_property_graph_tests.gt},{}) + type gt[] | (type,create_property_graph_tests,_gt,create_property_graph_tests.gt[]) | (type,{create_property_graph_tests.gt[]},{}) + vertex v1 of property graph gt | ("property graph element",,,"v1 of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,v1}",{}) + vertex v2 of property graph gt | ("property graph element",,,"v2 of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,v2}",{}) +(52 rows) + \a\t SELECT pg_get_propgraphdef('g2'::regclass); CREATE PROPERTY GRAPH create_property_graph_tests.g2 diff --git a/src/test/regress/expected/event_trigger.out b/src/test/regress/expected/event_trigger.out index 065f586310f..ed8d5df397e 100644 --- a/src/test/regress/expected/event_trigger.out +++ b/src/test/regress/expected/event_trigger.out @@ -173,6 +173,23 @@ NOTICE: test_event_trigger: ddl_command_end CREATE USER MAPPING alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; NOTICE: test_event_trigger: ddl_command_end ALTER DEFAULT PRIVILEGES +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE TABLE t2x (i int PRIMARY KEY, j text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); +NOTICE: test_event_trigger: ddl_command_end CREATE PROPERTY GRAPH +DROP PROPERTY GRAPH gx; +NOTICE: test_event_trigger: ddl_command_end DROP PROPERTY GRAPH +DROP TABLE t1x, t2x; +NOTICE: test_event_trigger: ddl_command_end DROP TABLE -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; ERROR: permission denied to change owner of event trigger "regress_event_trigger" diff --git a/src/test/regress/expected/object_address.out b/src/test/regress/expected/object_address.out index 97227d67a54..5e53f0b092e 100644 --- a/src/test/regress/expected/object_address.out +++ b/src/test/regress/expected/object_address.out @@ -67,7 +67,9 @@ DECLARE BEGIN FOR objtype IN VALUES ('toast table'), ('index column'), ('sequence column'), ('toast table column'), ('view column'), ('materialized view column'), - ('property graph element'), ('property graph label'), ('property graph property') + ('property graph element'), ('property graph element label'), + ('property graph label'), ('property graph label property'), + ('property graph property') LOOP BEGIN PERFORM pg_get_object_address(objtype, '{one}', '{}'); @@ -84,7 +86,9 @@ WARNING: error for toast table column: unsupported object type "toast table col WARNING: error for view column: unsupported object type "view column" WARNING: error for materialized view column: unsupported object type "materialized view column" WARNING: error for property graph element: unsupported object type "property graph element" +WARNING: error for property graph element label: unrecognized object type "property graph element label" WARNING: error for property graph label: unsupported object type "property graph label" +WARNING: error for property graph label property: unrecognized object type "property graph label property" WARNING: error for property graph property: unsupported object type "property graph property" -- miscellaneous other errors select * from pg_get_object_address('operator of access method', '{btree,integer_ops,1}', '{int4,bool}'); @@ -593,7 +597,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace @@ -653,6 +659,8 @@ ORDER BY objects.classid, objects.objid, objects.objsubid; ("(""parameter ACL"",,,)")|("(""parameter ACL"",,)")|NULL ("(""property graph element"",,,)")|("(""property graph element"",,)")|NULL ("(""property graph label"",,,)")|("(""property graph label"",,)")|NULL +("(""property graph element label"",,,)")|("(""property graph element label"",,)")|NULL ("(""property graph property"",,,)")|("(""property graph property"",,)")|NULL +("(""property graph label property"",,,)")|("(""property graph label property"",,)")|NULL -- restore normal output mode \a\t diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..9608dd5c4af 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -298,6 +298,29 @@ SELECT (pg_identify_object(classid, objid, objsubid)).* refobjid = 'create_property_graph_tests.g2'::regclass ORDER BY 1, 2, 3, 4; +-- test object address functions with recursive dependency walk +-- covers all property graph object types including indirect dependents +SELECT * +FROM ( + WITH RECURSIVE deps (classid, objid, objsubid, refclassid, refobjid, refobjsubid) AS ( + SELECT classid, objid, objsubid, + refclassid, refobjid, refobjsubid + FROM pg_depend + WHERE refclassid = 'pg_class'::regclass AND + refobjid = 'create_property_graph_tests.gt'::regclass + UNION ALL + SELECT d.classid, d.objid, d.objsubid, + d.refclassid, d.refobjid, d.refobjsubid + FROM pg_depend d + JOIN deps dp ON d.refclassid = dp.classid AND d.refobjid = dp.objid AND d.refobjsubid = dp.objsubid + ) + SELECT pg_describe_object(classid, objid, objsubid) as obj, + pg_identify_object(classid, objid, objsubid) as ident, + pg_identify_object_as_address(classid, objid, objsubid) as addr + FROM deps +) s +ORDER BY obj COLLATE "C", ident::text COLLATE "C"; + \a\t SELECT pg_get_propgraphdef('g2'::regclass); SELECT pg_get_propgraphdef('g3'::regclass); diff --git a/src/test/regress/sql/event_trigger.sql b/src/test/regress/sql/event_trigger.sql index 32e9bb58c5e..271f443378b 100644 --- a/src/test/regress/sql/event_trigger.sql +++ b/src/test/regress/sql/event_trigger.sql @@ -143,6 +143,19 @@ create user mapping for regress_evt_user server useless_server; alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +CREATE TABLE t2x (i int PRIMARY KEY, j text); + +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); + +DROP PROPERTY GRAPH gx; +DROP TABLE t1x, t2x; + -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; diff --git a/src/test/regress/sql/object_address.sql b/src/test/regress/sql/object_address.sql index 1bbe9457c1c..27109d421c7 100644 --- a/src/test/regress/sql/object_address.sql +++ b/src/test/regress/sql/object_address.sql @@ -67,7 +67,9 @@ DECLARE BEGIN FOR objtype IN VALUES ('toast table'), ('index column'), ('sequence column'), ('toast table column'), ('view column'), ('materialized view column'), - ('property graph element'), ('property graph label'), ('property graph property') + ('property graph element'), ('property graph element label'), + ('property graph label'), ('property graph label property'), + ('property graph property') LOOP BEGIN PERFORM pg_get_object_address(objtype, '{one}', '{}'); @@ -282,7 +284,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace -- 2.34.1 --R84XrR4Hgw0dH3Ec-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v2] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-23 09:27 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-23 09:27 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing them to hit the default case and error out with "unsupported object class". During DROP PROPERTY GRAPH, this manifests when an event trigger is active, because pg_event_trigger_ddl_commands() calls these functions. The same code paths are also reachable via pg_identify_object() and pg_identify_object_as_address(). This commit adds the missing cases. Test coverage is added in object_address.sql for these two catalog types via the zero-OID test that exercises pg_identify_object() and pg_identify_object_as_address(). A test in event_trigger.sql verifies that DROP PROPERTY GRAPH works correctly when an event trigger is active. Author: Bertrand Drouvot <[email protected]> Reviewed-by: Michael Paquier <[email protected]> Reviewed-by: Ashutosh Bapat <[email protected]> Discussion: https://postgr.es/m/aej1DkLwhyZWmtxJ@bdtpg --- src/backend/catalog/objectaddress.c | 93 ++++++++++++++++++++ src/test/regress/expected/event_trigger.out | 17 ++++ src/test/regress/expected/object_address.out | 4 + src/test/regress/sql/event_trigger.sql | 13 +++ src/test/regress/sql/object_address.sql | 2 + 5 files changed, 129 insertions(+) 62.4% src/backend/catalog/ 25.6% src/test/regress/expected/ 11.8% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/event_trigger.out b/src/test/regress/expected/event_trigger.out index 065f586310f..ed8d5df397e 100644 --- a/src/test/regress/expected/event_trigger.out +++ b/src/test/regress/expected/event_trigger.out @@ -173,6 +173,23 @@ NOTICE: test_event_trigger: ddl_command_end CREATE USER MAPPING alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; NOTICE: test_event_trigger: ddl_command_end ALTER DEFAULT PRIVILEGES +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE TABLE t2x (i int PRIMARY KEY, j text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); +NOTICE: test_event_trigger: ddl_command_end CREATE PROPERTY GRAPH +DROP PROPERTY GRAPH gx; +NOTICE: test_event_trigger: ddl_command_end DROP PROPERTY GRAPH +DROP TABLE t1x, t2x; +NOTICE: test_event_trigger: ddl_command_end DROP TABLE -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; ERROR: permission denied to change owner of event trigger "regress_event_trigger" diff --git a/src/test/regress/expected/object_address.out b/src/test/regress/expected/object_address.out index 97227d67a54..729c3537f25 100644 --- a/src/test/regress/expected/object_address.out +++ b/src/test/regress/expected/object_address.out @@ -593,7 +593,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace @@ -653,6 +655,8 @@ ORDER BY objects.classid, objects.objid, objects.objsubid; ("(""parameter ACL"",,,)")|("(""parameter ACL"",,)")|NULL ("(""property graph element"",,,)")|("(""property graph element"",,)")|NULL ("(""property graph label"",,,)")|("(""property graph label"",,)")|NULL +("(""property graph element label"",,,)")|("(""property graph element label"",,)")|NULL ("(""property graph property"",,,)")|("(""property graph property"",,)")|NULL +("(""property graph label property"",,,)")|("(""property graph label property"",,)")|NULL -- restore normal output mode \a\t diff --git a/src/test/regress/sql/event_trigger.sql b/src/test/regress/sql/event_trigger.sql index 32e9bb58c5e..271f443378b 100644 --- a/src/test/regress/sql/event_trigger.sql +++ b/src/test/regress/sql/event_trigger.sql @@ -143,6 +143,19 @@ create user mapping for regress_evt_user server useless_server; alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +CREATE TABLE t2x (i int PRIMARY KEY, j text); + +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); + +DROP PROPERTY GRAPH gx; +DROP TABLE t1x, t2x; + -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; diff --git a/src/test/regress/sql/object_address.sql b/src/test/regress/sql/object_address.sql index 1bbe9457c1c..620dacf1045 100644 --- a/src/test/regress/sql/object_address.sql +++ b/src/test/regress/sql/object_address.sql @@ -282,7 +282,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace -- 2.34.1 --gtUR827Uq8d5gVsQ-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v3] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-23 09:27 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-23 09:27 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing them to hit the default case and error out with "unsupported object class". During DROP PROPERTY GRAPH, this manifests when an event trigger is active, because pg_event_trigger_ddl_commands() calls these functions. The same code paths are also reachable via pg_identify_object() and pg_identify_object_as_address(). This commit adds the missing cases. Test coverage is added in object_address.sql for these two catalog types and in create_property_graph.sql covering all property graph object types. A test in event_trigger.sql verifies that DROP PROPERTY GRAPH works correctly when an event trigger is active. Author: Bertrand Drouvot <[email protected]> Reviewed-by: Michael Paquier <[email protected]> Reviewed-by: Ashutosh Bapat <[email protected]> Discussion: https://postgr.es/m/aej1DkLwhyZWmtxJ@bdtpg --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 78 ++++++++++++++++ src/test/regress/expected/event_trigger.out | 17 ++++ src/test/regress/expected/object_address.out | 10 +- .../regress/sql/create_property_graph.sql | 23 +++++ src/test/regress/sql/event_trigger.sql | 13 +++ src/test/regress/sql/object_address.sql | 6 +- 7 files changed, 238 insertions(+), 2 deletions(-) 14.7% src/backend/catalog/ 75.5% src/test/regress/expected/ 9.7% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..eb9e17fb727 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -752,6 +752,84 @@ SELECT (pg_identify_object(classid, objid, objsubid)).* type | create_property_graph_tests | g2 | create_property_graph_tests.g2 (21 rows) +-- test object address functions with recursive dependency walk +-- covers all property graph object types including indirect dependents +SELECT * +FROM ( + WITH RECURSIVE deps (classid, objid, objsubid, refclassid, refobjid, refobjsubid) AS ( + SELECT classid, objid, objsubid, + refclassid, refobjid, refobjsubid + FROM pg_depend + WHERE refclassid = 'pg_class'::regclass AND + refobjid = 'create_property_graph_tests.gt'::regclass + UNION ALL + SELECT d.classid, d.objid, d.objsubid, + d.refclassid, d.refobjid, d.refobjsubid + FROM pg_depend d + JOIN deps dp ON d.refclassid = dp.classid AND d.refobjid = dp.objid AND d.refobjsubid = dp.objsubid + ) + SELECT pg_describe_object(classid, objid, objsubid) as obj, + pg_identify_object(classid, objid, objsubid) as ident, + pg_identify_object_as_address(classid, objid, objsubid) as addr + FROM deps +) s +ORDER BY obj COLLATE "C", ident::text COLLATE "C"; + obj | ident | addr +----------------------------------------------------------+----------------------------------------------------------------------------+---------------------------------------------------------------------------- + edge e of property graph gt | ("property graph element",,,"e of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,e}",{}) + edge e of property graph gt | ("property graph element",,,"e of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,e}",{}) + edge e of property graph gt | ("property graph element",,,"e of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of property graph gt | ("property graph label",,,"e of create_property_graph_tests.gt") | ("property graph label","{create_property_graph_tests,gt,e}",{}) + label v1 of property graph gt | ("property graph label",,,"v1 of create_property_graph_tests.gt") | ("property graph label","{create_property_graph_tests,gt,v1}",{}) + label v1 of vertex v1 of property graph gt | ("property graph element label",,,"v1 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v1}",{}) + label v1 of vertex v1 of property graph gt | ("property graph element label",,,"v1 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v1}",{}) + label v2 of property graph gt | ("property graph label",,,"v2 of create_property_graph_tests.gt") | ("property graph label","{create_property_graph_tests,gt,v2}",{}) + label v2 of vertex v2 of property graph gt | ("property graph element label",,,"v2 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v2}",{}) + label v2 of vertex v2 of property graph gt | ("property graph element label",,,"v2 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v2}",{}) + property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property a of property graph gt | ("property graph property",,,"a of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,a}",{}) + property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property b of property graph gt | ("property graph property",,,"b of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,b}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of property graph gt | ("property graph property",,,"c of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,c}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of property graph gt | ("property graph property",,,"k1 of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,k1}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of property graph gt | ("property graph property",,,"k2 of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,k2}",{}) + property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property m of property graph gt | ("property graph property",,,"m of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,m}",{}) + property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property n of property graph gt | ("property graph property",,,"n of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,n}",{}) + type gt | (type,create_property_graph_tests,gt,create_property_graph_tests.gt) | (type,{create_property_graph_tests.gt},{}) + type gt[] | (type,create_property_graph_tests,_gt,create_property_graph_tests.gt[]) | (type,{create_property_graph_tests.gt[]},{}) + vertex v1 of property graph gt | ("property graph element",,,"v1 of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,v1}",{}) + vertex v2 of property graph gt | ("property graph element",,,"v2 of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,v2}",{}) +(52 rows) + \a\t SELECT pg_get_propgraphdef('g2'::regclass); CREATE PROPERTY GRAPH create_property_graph_tests.g2 diff --git a/src/test/regress/expected/event_trigger.out b/src/test/regress/expected/event_trigger.out index 065f586310f..ed8d5df397e 100644 --- a/src/test/regress/expected/event_trigger.out +++ b/src/test/regress/expected/event_trigger.out @@ -173,6 +173,23 @@ NOTICE: test_event_trigger: ddl_command_end CREATE USER MAPPING alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; NOTICE: test_event_trigger: ddl_command_end ALTER DEFAULT PRIVILEGES +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE TABLE t2x (i int PRIMARY KEY, j text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); +NOTICE: test_event_trigger: ddl_command_end CREATE PROPERTY GRAPH +DROP PROPERTY GRAPH gx; +NOTICE: test_event_trigger: ddl_command_end DROP PROPERTY GRAPH +DROP TABLE t1x, t2x; +NOTICE: test_event_trigger: ddl_command_end DROP TABLE -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; ERROR: permission denied to change owner of event trigger "regress_event_trigger" diff --git a/src/test/regress/expected/object_address.out b/src/test/regress/expected/object_address.out index 97227d67a54..5e53f0b092e 100644 --- a/src/test/regress/expected/object_address.out +++ b/src/test/regress/expected/object_address.out @@ -67,7 +67,9 @@ DECLARE BEGIN FOR objtype IN VALUES ('toast table'), ('index column'), ('sequence column'), ('toast table column'), ('view column'), ('materialized view column'), - ('property graph element'), ('property graph label'), ('property graph property') + ('property graph element'), ('property graph element label'), + ('property graph label'), ('property graph label property'), + ('property graph property') LOOP BEGIN PERFORM pg_get_object_address(objtype, '{one}', '{}'); @@ -84,7 +86,9 @@ WARNING: error for toast table column: unsupported object type "toast table col WARNING: error for view column: unsupported object type "view column" WARNING: error for materialized view column: unsupported object type "materialized view column" WARNING: error for property graph element: unsupported object type "property graph element" +WARNING: error for property graph element label: unrecognized object type "property graph element label" WARNING: error for property graph label: unsupported object type "property graph label" +WARNING: error for property graph label property: unrecognized object type "property graph label property" WARNING: error for property graph property: unsupported object type "property graph property" -- miscellaneous other errors select * from pg_get_object_address('operator of access method', '{btree,integer_ops,1}', '{int4,bool}'); @@ -593,7 +597,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace @@ -653,6 +659,8 @@ ORDER BY objects.classid, objects.objid, objects.objsubid; ("(""parameter ACL"",,,)")|("(""parameter ACL"",,)")|NULL ("(""property graph element"",,,)")|("(""property graph element"",,)")|NULL ("(""property graph label"",,,)")|("(""property graph label"",,)")|NULL +("(""property graph element label"",,,)")|("(""property graph element label"",,)")|NULL ("(""property graph property"",,,)")|("(""property graph property"",,)")|NULL +("(""property graph label property"",,,)")|("(""property graph label property"",,)")|NULL -- restore normal output mode \a\t diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..9608dd5c4af 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -298,6 +298,29 @@ SELECT (pg_identify_object(classid, objid, objsubid)).* refobjid = 'create_property_graph_tests.g2'::regclass ORDER BY 1, 2, 3, 4; +-- test object address functions with recursive dependency walk +-- covers all property graph object types including indirect dependents +SELECT * +FROM ( + WITH RECURSIVE deps (classid, objid, objsubid, refclassid, refobjid, refobjsubid) AS ( + SELECT classid, objid, objsubid, + refclassid, refobjid, refobjsubid + FROM pg_depend + WHERE refclassid = 'pg_class'::regclass AND + refobjid = 'create_property_graph_tests.gt'::regclass + UNION ALL + SELECT d.classid, d.objid, d.objsubid, + d.refclassid, d.refobjid, d.refobjsubid + FROM pg_depend d + JOIN deps dp ON d.refclassid = dp.classid AND d.refobjid = dp.objid AND d.refobjsubid = dp.objsubid + ) + SELECT pg_describe_object(classid, objid, objsubid) as obj, + pg_identify_object(classid, objid, objsubid) as ident, + pg_identify_object_as_address(classid, objid, objsubid) as addr + FROM deps +) s +ORDER BY obj COLLATE "C", ident::text COLLATE "C"; + \a\t SELECT pg_get_propgraphdef('g2'::regclass); SELECT pg_get_propgraphdef('g3'::regclass); diff --git a/src/test/regress/sql/event_trigger.sql b/src/test/regress/sql/event_trigger.sql index 32e9bb58c5e..271f443378b 100644 --- a/src/test/regress/sql/event_trigger.sql +++ b/src/test/regress/sql/event_trigger.sql @@ -143,6 +143,19 @@ create user mapping for regress_evt_user server useless_server; alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +CREATE TABLE t2x (i int PRIMARY KEY, j text); + +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); + +DROP PROPERTY GRAPH gx; +DROP TABLE t1x, t2x; + -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; diff --git a/src/test/regress/sql/object_address.sql b/src/test/regress/sql/object_address.sql index 1bbe9457c1c..27109d421c7 100644 --- a/src/test/regress/sql/object_address.sql +++ b/src/test/regress/sql/object_address.sql @@ -67,7 +67,9 @@ DECLARE BEGIN FOR objtype IN VALUES ('toast table'), ('index column'), ('sequence column'), ('toast table column'), ('view column'), ('materialized view column'), - ('property graph element'), ('property graph label'), ('property graph property') + ('property graph element'), ('property graph element label'), + ('property graph label'), ('property graph label property'), + ('property graph property') LOOP BEGIN PERFORM pg_get_object_address(objtype, '{one}', '{}'); @@ -282,7 +284,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace -- 2.34.1 --R84XrR4Hgw0dH3Ec-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v3] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-23 09:27 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-23 09:27 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing them to hit the default case and error out with "unsupported object class". During DROP PROPERTY GRAPH, this manifests when an event trigger is active, because pg_event_trigger_ddl_commands() calls these functions. The same code paths are also reachable via pg_identify_object() and pg_identify_object_as_address(). This commit adds the missing cases. Test coverage is added in object_address.sql for these two catalog types and in create_property_graph.sql covering all property graph object types. A test in event_trigger.sql verifies that DROP PROPERTY GRAPH works correctly when an event trigger is active. Author: Bertrand Drouvot <[email protected]> Reviewed-by: Michael Paquier <[email protected]> Reviewed-by: Ashutosh Bapat <[email protected]> Discussion: https://postgr.es/m/aej1DkLwhyZWmtxJ@bdtpg --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 78 ++++++++++++++++ src/test/regress/expected/event_trigger.out | 17 ++++ src/test/regress/expected/object_address.out | 10 +- .../regress/sql/create_property_graph.sql | 23 +++++ src/test/regress/sql/event_trigger.sql | 13 +++ src/test/regress/sql/object_address.sql | 6 +- 7 files changed, 238 insertions(+), 2 deletions(-) 14.7% src/backend/catalog/ 75.5% src/test/regress/expected/ 9.7% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..eb9e17fb727 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -752,6 +752,84 @@ SELECT (pg_identify_object(classid, objid, objsubid)).* type | create_property_graph_tests | g2 | create_property_graph_tests.g2 (21 rows) +-- test object address functions with recursive dependency walk +-- covers all property graph object types including indirect dependents +SELECT * +FROM ( + WITH RECURSIVE deps (classid, objid, objsubid, refclassid, refobjid, refobjsubid) AS ( + SELECT classid, objid, objsubid, + refclassid, refobjid, refobjsubid + FROM pg_depend + WHERE refclassid = 'pg_class'::regclass AND + refobjid = 'create_property_graph_tests.gt'::regclass + UNION ALL + SELECT d.classid, d.objid, d.objsubid, + d.refclassid, d.refobjid, d.refobjsubid + FROM pg_depend d + JOIN deps dp ON d.refclassid = dp.classid AND d.refobjid = dp.objid AND d.refobjsubid = dp.objsubid + ) + SELECT pg_describe_object(classid, objid, objsubid) as obj, + pg_identify_object(classid, objid, objsubid) as ident, + pg_identify_object_as_address(classid, objid, objsubid) as addr + FROM deps +) s +ORDER BY obj COLLATE "C", ident::text COLLATE "C"; + obj | ident | addr +----------------------------------------------------------+----------------------------------------------------------------------------+---------------------------------------------------------------------------- + edge e of property graph gt | ("property graph element",,,"e of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,e}",{}) + edge e of property graph gt | ("property graph element",,,"e of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,e}",{}) + edge e of property graph gt | ("property graph element",,,"e of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of property graph gt | ("property graph label",,,"e of create_property_graph_tests.gt") | ("property graph label","{create_property_graph_tests,gt,e}",{}) + label v1 of property graph gt | ("property graph label",,,"v1 of create_property_graph_tests.gt") | ("property graph label","{create_property_graph_tests,gt,v1}",{}) + label v1 of vertex v1 of property graph gt | ("property graph element label",,,"v1 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v1}",{}) + label v1 of vertex v1 of property graph gt | ("property graph element label",,,"v1 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v1}",{}) + label v2 of property graph gt | ("property graph label",,,"v2 of create_property_graph_tests.gt") | ("property graph label","{create_property_graph_tests,gt,v2}",{}) + label v2 of vertex v2 of property graph gt | ("property graph element label",,,"v2 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v2}",{}) + label v2 of vertex v2 of property graph gt | ("property graph element label",,,"v2 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v2}",{}) + property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property a of property graph gt | ("property graph property",,,"a of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,a}",{}) + property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property b of property graph gt | ("property graph property",,,"b of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,b}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of property graph gt | ("property graph property",,,"c of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,c}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of property graph gt | ("property graph property",,,"k1 of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,k1}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of property graph gt | ("property graph property",,,"k2 of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,k2}",{}) + property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property m of property graph gt | ("property graph property",,,"m of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,m}",{}) + property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property n of property graph gt | ("property graph property",,,"n of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,n}",{}) + type gt | (type,create_property_graph_tests,gt,create_property_graph_tests.gt) | (type,{create_property_graph_tests.gt},{}) + type gt[] | (type,create_property_graph_tests,_gt,create_property_graph_tests.gt[]) | (type,{create_property_graph_tests.gt[]},{}) + vertex v1 of property graph gt | ("property graph element",,,"v1 of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,v1}",{}) + vertex v2 of property graph gt | ("property graph element",,,"v2 of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,v2}",{}) +(52 rows) + \a\t SELECT pg_get_propgraphdef('g2'::regclass); CREATE PROPERTY GRAPH create_property_graph_tests.g2 diff --git a/src/test/regress/expected/event_trigger.out b/src/test/regress/expected/event_trigger.out index 065f586310f..ed8d5df397e 100644 --- a/src/test/regress/expected/event_trigger.out +++ b/src/test/regress/expected/event_trigger.out @@ -173,6 +173,23 @@ NOTICE: test_event_trigger: ddl_command_end CREATE USER MAPPING alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; NOTICE: test_event_trigger: ddl_command_end ALTER DEFAULT PRIVILEGES +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE TABLE t2x (i int PRIMARY KEY, j text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); +NOTICE: test_event_trigger: ddl_command_end CREATE PROPERTY GRAPH +DROP PROPERTY GRAPH gx; +NOTICE: test_event_trigger: ddl_command_end DROP PROPERTY GRAPH +DROP TABLE t1x, t2x; +NOTICE: test_event_trigger: ddl_command_end DROP TABLE -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; ERROR: permission denied to change owner of event trigger "regress_event_trigger" diff --git a/src/test/regress/expected/object_address.out b/src/test/regress/expected/object_address.out index 97227d67a54..5e53f0b092e 100644 --- a/src/test/regress/expected/object_address.out +++ b/src/test/regress/expected/object_address.out @@ -67,7 +67,9 @@ DECLARE BEGIN FOR objtype IN VALUES ('toast table'), ('index column'), ('sequence column'), ('toast table column'), ('view column'), ('materialized view column'), - ('property graph element'), ('property graph label'), ('property graph property') + ('property graph element'), ('property graph element label'), + ('property graph label'), ('property graph label property'), + ('property graph property') LOOP BEGIN PERFORM pg_get_object_address(objtype, '{one}', '{}'); @@ -84,7 +86,9 @@ WARNING: error for toast table column: unsupported object type "toast table col WARNING: error for view column: unsupported object type "view column" WARNING: error for materialized view column: unsupported object type "materialized view column" WARNING: error for property graph element: unsupported object type "property graph element" +WARNING: error for property graph element label: unrecognized object type "property graph element label" WARNING: error for property graph label: unsupported object type "property graph label" +WARNING: error for property graph label property: unrecognized object type "property graph label property" WARNING: error for property graph property: unsupported object type "property graph property" -- miscellaneous other errors select * from pg_get_object_address('operator of access method', '{btree,integer_ops,1}', '{int4,bool}'); @@ -593,7 +597,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace @@ -653,6 +659,8 @@ ORDER BY objects.classid, objects.objid, objects.objsubid; ("(""parameter ACL"",,,)")|("(""parameter ACL"",,)")|NULL ("(""property graph element"",,,)")|("(""property graph element"",,)")|NULL ("(""property graph label"",,,)")|("(""property graph label"",,)")|NULL +("(""property graph element label"",,,)")|("(""property graph element label"",,)")|NULL ("(""property graph property"",,,)")|("(""property graph property"",,)")|NULL +("(""property graph label property"",,,)")|("(""property graph label property"",,)")|NULL -- restore normal output mode \a\t diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..9608dd5c4af 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -298,6 +298,29 @@ SELECT (pg_identify_object(classid, objid, objsubid)).* refobjid = 'create_property_graph_tests.g2'::regclass ORDER BY 1, 2, 3, 4; +-- test object address functions with recursive dependency walk +-- covers all property graph object types including indirect dependents +SELECT * +FROM ( + WITH RECURSIVE deps (classid, objid, objsubid, refclassid, refobjid, refobjsubid) AS ( + SELECT classid, objid, objsubid, + refclassid, refobjid, refobjsubid + FROM pg_depend + WHERE refclassid = 'pg_class'::regclass AND + refobjid = 'create_property_graph_tests.gt'::regclass + UNION ALL + SELECT d.classid, d.objid, d.objsubid, + d.refclassid, d.refobjid, d.refobjsubid + FROM pg_depend d + JOIN deps dp ON d.refclassid = dp.classid AND d.refobjid = dp.objid AND d.refobjsubid = dp.objsubid + ) + SELECT pg_describe_object(classid, objid, objsubid) as obj, + pg_identify_object(classid, objid, objsubid) as ident, + pg_identify_object_as_address(classid, objid, objsubid) as addr + FROM deps +) s +ORDER BY obj COLLATE "C", ident::text COLLATE "C"; + \a\t SELECT pg_get_propgraphdef('g2'::regclass); SELECT pg_get_propgraphdef('g3'::regclass); diff --git a/src/test/regress/sql/event_trigger.sql b/src/test/regress/sql/event_trigger.sql index 32e9bb58c5e..271f443378b 100644 --- a/src/test/regress/sql/event_trigger.sql +++ b/src/test/regress/sql/event_trigger.sql @@ -143,6 +143,19 @@ create user mapping for regress_evt_user server useless_server; alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +CREATE TABLE t2x (i int PRIMARY KEY, j text); + +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); + +DROP PROPERTY GRAPH gx; +DROP TABLE t1x, t2x; + -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; diff --git a/src/test/regress/sql/object_address.sql b/src/test/regress/sql/object_address.sql index 1bbe9457c1c..27109d421c7 100644 --- a/src/test/regress/sql/object_address.sql +++ b/src/test/regress/sql/object_address.sql @@ -67,7 +67,9 @@ DECLARE BEGIN FOR objtype IN VALUES ('toast table'), ('index column'), ('sequence column'), ('toast table column'), ('view column'), ('materialized view column'), - ('property graph element'), ('property graph label'), ('property graph property') + ('property graph element'), ('property graph element label'), + ('property graph label'), ('property graph label property'), + ('property graph property') LOOP BEGIN PERFORM pg_get_object_address(objtype, '{one}', '{}'); @@ -282,7 +284,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace -- 2.34.1 --R84XrR4Hgw0dH3Ec-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v2] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-23 09:27 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-23 09:27 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing them to hit the default case and error out with "unsupported object class". During DROP PROPERTY GRAPH, this manifests when an event trigger is active, because pg_event_trigger_ddl_commands() calls these functions. The same code paths are also reachable via pg_identify_object() and pg_identify_object_as_address(). This commit adds the missing cases. Test coverage is added in object_address.sql for these two catalog types via the zero-OID test that exercises pg_identify_object() and pg_identify_object_as_address(). A test in event_trigger.sql verifies that DROP PROPERTY GRAPH works correctly when an event trigger is active. Author: Bertrand Drouvot <[email protected]> Reviewed-by: Michael Paquier <[email protected]> Reviewed-by: Ashutosh Bapat <[email protected]> Discussion: https://postgr.es/m/aej1DkLwhyZWmtxJ@bdtpg --- src/backend/catalog/objectaddress.c | 93 ++++++++++++++++++++ src/test/regress/expected/event_trigger.out | 17 ++++ src/test/regress/expected/object_address.out | 4 + src/test/regress/sql/event_trigger.sql | 13 +++ src/test/regress/sql/object_address.sql | 2 + 5 files changed, 129 insertions(+) 62.4% src/backend/catalog/ 25.6% src/test/regress/expected/ 11.8% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/event_trigger.out b/src/test/regress/expected/event_trigger.out index 065f586310f..ed8d5df397e 100644 --- a/src/test/regress/expected/event_trigger.out +++ b/src/test/regress/expected/event_trigger.out @@ -173,6 +173,23 @@ NOTICE: test_event_trigger: ddl_command_end CREATE USER MAPPING alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; NOTICE: test_event_trigger: ddl_command_end ALTER DEFAULT PRIVILEGES +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE TABLE t2x (i int PRIMARY KEY, j text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); +NOTICE: test_event_trigger: ddl_command_end CREATE PROPERTY GRAPH +DROP PROPERTY GRAPH gx; +NOTICE: test_event_trigger: ddl_command_end DROP PROPERTY GRAPH +DROP TABLE t1x, t2x; +NOTICE: test_event_trigger: ddl_command_end DROP TABLE -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; ERROR: permission denied to change owner of event trigger "regress_event_trigger" diff --git a/src/test/regress/expected/object_address.out b/src/test/regress/expected/object_address.out index 97227d67a54..729c3537f25 100644 --- a/src/test/regress/expected/object_address.out +++ b/src/test/regress/expected/object_address.out @@ -593,7 +593,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace @@ -653,6 +655,8 @@ ORDER BY objects.classid, objects.objid, objects.objsubid; ("(""parameter ACL"",,,)")|("(""parameter ACL"",,)")|NULL ("(""property graph element"",,,)")|("(""property graph element"",,)")|NULL ("(""property graph label"",,,)")|("(""property graph label"",,)")|NULL +("(""property graph element label"",,,)")|("(""property graph element label"",,)")|NULL ("(""property graph property"",,,)")|("(""property graph property"",,)")|NULL +("(""property graph label property"",,,)")|("(""property graph label property"",,)")|NULL -- restore normal output mode \a\t diff --git a/src/test/regress/sql/event_trigger.sql b/src/test/regress/sql/event_trigger.sql index 32e9bb58c5e..271f443378b 100644 --- a/src/test/regress/sql/event_trigger.sql +++ b/src/test/regress/sql/event_trigger.sql @@ -143,6 +143,19 @@ create user mapping for regress_evt_user server useless_server; alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +CREATE TABLE t2x (i int PRIMARY KEY, j text); + +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); + +DROP PROPERTY GRAPH gx; +DROP TABLE t1x, t2x; + -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; diff --git a/src/test/regress/sql/object_address.sql b/src/test/regress/sql/object_address.sql index 1bbe9457c1c..620dacf1045 100644 --- a/src/test/regress/sql/object_address.sql +++ b/src/test/regress/sql/object_address.sql @@ -282,7 +282,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace -- 2.34.1 --gtUR827Uq8d5gVsQ-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v2] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-23 09:27 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-23 09:27 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing them to hit the default case and error out with "unsupported object class". During DROP PROPERTY GRAPH, this manifests when an event trigger is active, because pg_event_trigger_ddl_commands() calls these functions. The same code paths are also reachable via pg_identify_object() and pg_identify_object_as_address(). This commit adds the missing cases. Test coverage is added in object_address.sql for these two catalog types via the zero-OID test that exercises pg_identify_object() and pg_identify_object_as_address(). A test in event_trigger.sql verifies that DROP PROPERTY GRAPH works correctly when an event trigger is active. Author: Bertrand Drouvot <[email protected]> Reviewed-by: Michael Paquier <[email protected]> Reviewed-by: Ashutosh Bapat <[email protected]> Discussion: https://postgr.es/m/aej1DkLwhyZWmtxJ@bdtpg --- src/backend/catalog/objectaddress.c | 93 ++++++++++++++++++++ src/test/regress/expected/event_trigger.out | 17 ++++ src/test/regress/expected/object_address.out | 4 + src/test/regress/sql/event_trigger.sql | 13 +++ src/test/regress/sql/object_address.sql | 2 + 5 files changed, 129 insertions(+) 62.4% src/backend/catalog/ 25.6% src/test/regress/expected/ 11.8% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/event_trigger.out b/src/test/regress/expected/event_trigger.out index 065f586310f..ed8d5df397e 100644 --- a/src/test/regress/expected/event_trigger.out +++ b/src/test/regress/expected/event_trigger.out @@ -173,6 +173,23 @@ NOTICE: test_event_trigger: ddl_command_end CREATE USER MAPPING alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; NOTICE: test_event_trigger: ddl_command_end ALTER DEFAULT PRIVILEGES +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE TABLE t2x (i int PRIMARY KEY, j text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); +NOTICE: test_event_trigger: ddl_command_end CREATE PROPERTY GRAPH +DROP PROPERTY GRAPH gx; +NOTICE: test_event_trigger: ddl_command_end DROP PROPERTY GRAPH +DROP TABLE t1x, t2x; +NOTICE: test_event_trigger: ddl_command_end DROP TABLE -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; ERROR: permission denied to change owner of event trigger "regress_event_trigger" diff --git a/src/test/regress/expected/object_address.out b/src/test/regress/expected/object_address.out index 97227d67a54..729c3537f25 100644 --- a/src/test/regress/expected/object_address.out +++ b/src/test/regress/expected/object_address.out @@ -593,7 +593,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace @@ -653,6 +655,8 @@ ORDER BY objects.classid, objects.objid, objects.objsubid; ("(""parameter ACL"",,,)")|("(""parameter ACL"",,)")|NULL ("(""property graph element"",,,)")|("(""property graph element"",,)")|NULL ("(""property graph label"",,,)")|("(""property graph label"",,)")|NULL +("(""property graph element label"",,,)")|("(""property graph element label"",,)")|NULL ("(""property graph property"",,,)")|("(""property graph property"",,)")|NULL +("(""property graph label property"",,,)")|("(""property graph label property"",,)")|NULL -- restore normal output mode \a\t diff --git a/src/test/regress/sql/event_trigger.sql b/src/test/regress/sql/event_trigger.sql index 32e9bb58c5e..271f443378b 100644 --- a/src/test/regress/sql/event_trigger.sql +++ b/src/test/regress/sql/event_trigger.sql @@ -143,6 +143,19 @@ create user mapping for regress_evt_user server useless_server; alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +CREATE TABLE t2x (i int PRIMARY KEY, j text); + +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); + +DROP PROPERTY GRAPH gx; +DROP TABLE t1x, t2x; + -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; diff --git a/src/test/regress/sql/object_address.sql b/src/test/regress/sql/object_address.sql index 1bbe9457c1c..620dacf1045 100644 --- a/src/test/regress/sql/object_address.sql +++ b/src/test/regress/sql/object_address.sql @@ -282,7 +282,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace -- 2.34.1 --gtUR827Uq8d5gVsQ-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v2] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-23 09:27 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-23 09:27 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing them to hit the default case and error out with "unsupported object class". During DROP PROPERTY GRAPH, this manifests when an event trigger is active, because pg_event_trigger_ddl_commands() calls these functions. The same code paths are also reachable via pg_identify_object() and pg_identify_object_as_address(). This commit adds the missing cases. Test coverage is added in object_address.sql for these two catalog types via the zero-OID test that exercises pg_identify_object() and pg_identify_object_as_address(). A test in event_trigger.sql verifies that DROP PROPERTY GRAPH works correctly when an event trigger is active. Author: Bertrand Drouvot <[email protected]> Reviewed-by: Michael Paquier <[email protected]> Reviewed-by: Ashutosh Bapat <[email protected]> Discussion: https://postgr.es/m/aej1DkLwhyZWmtxJ@bdtpg --- src/backend/catalog/objectaddress.c | 93 ++++++++++++++++++++ src/test/regress/expected/event_trigger.out | 17 ++++ src/test/regress/expected/object_address.out | 4 + src/test/regress/sql/event_trigger.sql | 13 +++ src/test/regress/sql/object_address.sql | 2 + 5 files changed, 129 insertions(+) 62.4% src/backend/catalog/ 25.6% src/test/regress/expected/ 11.8% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/event_trigger.out b/src/test/regress/expected/event_trigger.out index 065f586310f..ed8d5df397e 100644 --- a/src/test/regress/expected/event_trigger.out +++ b/src/test/regress/expected/event_trigger.out @@ -173,6 +173,23 @@ NOTICE: test_event_trigger: ddl_command_end CREATE USER MAPPING alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; NOTICE: test_event_trigger: ddl_command_end ALTER DEFAULT PRIVILEGES +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE TABLE t2x (i int PRIMARY KEY, j text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); +NOTICE: test_event_trigger: ddl_command_end CREATE PROPERTY GRAPH +DROP PROPERTY GRAPH gx; +NOTICE: test_event_trigger: ddl_command_end DROP PROPERTY GRAPH +DROP TABLE t1x, t2x; +NOTICE: test_event_trigger: ddl_command_end DROP TABLE -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; ERROR: permission denied to change owner of event trigger "regress_event_trigger" diff --git a/src/test/regress/expected/object_address.out b/src/test/regress/expected/object_address.out index 97227d67a54..729c3537f25 100644 --- a/src/test/regress/expected/object_address.out +++ b/src/test/regress/expected/object_address.out @@ -593,7 +593,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace @@ -653,6 +655,8 @@ ORDER BY objects.classid, objects.objid, objects.objsubid; ("(""parameter ACL"",,,)")|("(""parameter ACL"",,)")|NULL ("(""property graph element"",,,)")|("(""property graph element"",,)")|NULL ("(""property graph label"",,,)")|("(""property graph label"",,)")|NULL +("(""property graph element label"",,,)")|("(""property graph element label"",,)")|NULL ("(""property graph property"",,,)")|("(""property graph property"",,)")|NULL +("(""property graph label property"",,,)")|("(""property graph label property"",,)")|NULL -- restore normal output mode \a\t diff --git a/src/test/regress/sql/event_trigger.sql b/src/test/regress/sql/event_trigger.sql index 32e9bb58c5e..271f443378b 100644 --- a/src/test/regress/sql/event_trigger.sql +++ b/src/test/regress/sql/event_trigger.sql @@ -143,6 +143,19 @@ create user mapping for regress_evt_user server useless_server; alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +CREATE TABLE t2x (i int PRIMARY KEY, j text); + +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); + +DROP PROPERTY GRAPH gx; +DROP TABLE t1x, t2x; + -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; diff --git a/src/test/regress/sql/object_address.sql b/src/test/regress/sql/object_address.sql index 1bbe9457c1c..620dacf1045 100644 --- a/src/test/regress/sql/object_address.sql +++ b/src/test/regress/sql/object_address.sql @@ -282,7 +282,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace -- 2.34.1 --gtUR827Uq8d5gVsQ-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v3] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-23 09:27 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-23 09:27 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing them to hit the default case and error out with "unsupported object class". During DROP PROPERTY GRAPH, this manifests when an event trigger is active, because pg_event_trigger_ddl_commands() calls these functions. The same code paths are also reachable via pg_identify_object() and pg_identify_object_as_address(). This commit adds the missing cases. Test coverage is added in object_address.sql for these two catalog types and in create_property_graph.sql covering all property graph object types. A test in event_trigger.sql verifies that DROP PROPERTY GRAPH works correctly when an event trigger is active. Author: Bertrand Drouvot <[email protected]> Reviewed-by: Michael Paquier <[email protected]> Reviewed-by: Ashutosh Bapat <[email protected]> Discussion: https://postgr.es/m/aej1DkLwhyZWmtxJ@bdtpg --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 78 ++++++++++++++++ src/test/regress/expected/event_trigger.out | 17 ++++ src/test/regress/expected/object_address.out | 10 +- .../regress/sql/create_property_graph.sql | 23 +++++ src/test/regress/sql/event_trigger.sql | 13 +++ src/test/regress/sql/object_address.sql | 6 +- 7 files changed, 238 insertions(+), 2 deletions(-) 14.7% src/backend/catalog/ 75.5% src/test/regress/expected/ 9.7% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..eb9e17fb727 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -752,6 +752,84 @@ SELECT (pg_identify_object(classid, objid, objsubid)).* type | create_property_graph_tests | g2 | create_property_graph_tests.g2 (21 rows) +-- test object address functions with recursive dependency walk +-- covers all property graph object types including indirect dependents +SELECT * +FROM ( + WITH RECURSIVE deps (classid, objid, objsubid, refclassid, refobjid, refobjsubid) AS ( + SELECT classid, objid, objsubid, + refclassid, refobjid, refobjsubid + FROM pg_depend + WHERE refclassid = 'pg_class'::regclass AND + refobjid = 'create_property_graph_tests.gt'::regclass + UNION ALL + SELECT d.classid, d.objid, d.objsubid, + d.refclassid, d.refobjid, d.refobjsubid + FROM pg_depend d + JOIN deps dp ON d.refclassid = dp.classid AND d.refobjid = dp.objid AND d.refobjsubid = dp.objsubid + ) + SELECT pg_describe_object(classid, objid, objsubid) as obj, + pg_identify_object(classid, objid, objsubid) as ident, + pg_identify_object_as_address(classid, objid, objsubid) as addr + FROM deps +) s +ORDER BY obj COLLATE "C", ident::text COLLATE "C"; + obj | ident | addr +----------------------------------------------------------+----------------------------------------------------------------------------+---------------------------------------------------------------------------- + edge e of property graph gt | ("property graph element",,,"e of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,e}",{}) + edge e of property graph gt | ("property graph element",,,"e of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,e}",{}) + edge e of property graph gt | ("property graph element",,,"e of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of property graph gt | ("property graph label",,,"e of create_property_graph_tests.gt") | ("property graph label","{create_property_graph_tests,gt,e}",{}) + label v1 of property graph gt | ("property graph label",,,"v1 of create_property_graph_tests.gt") | ("property graph label","{create_property_graph_tests,gt,v1}",{}) + label v1 of vertex v1 of property graph gt | ("property graph element label",,,"v1 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v1}",{}) + label v1 of vertex v1 of property graph gt | ("property graph element label",,,"v1 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v1}",{}) + label v2 of property graph gt | ("property graph label",,,"v2 of create_property_graph_tests.gt") | ("property graph label","{create_property_graph_tests,gt,v2}",{}) + label v2 of vertex v2 of property graph gt | ("property graph element label",,,"v2 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v2}",{}) + label v2 of vertex v2 of property graph gt | ("property graph element label",,,"v2 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v2}",{}) + property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property a of property graph gt | ("property graph property",,,"a of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,a}",{}) + property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property b of property graph gt | ("property graph property",,,"b of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,b}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of property graph gt | ("property graph property",,,"c of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,c}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of property graph gt | ("property graph property",,,"k1 of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,k1}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of property graph gt | ("property graph property",,,"k2 of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,k2}",{}) + property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property m of property graph gt | ("property graph property",,,"m of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,m}",{}) + property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property n of property graph gt | ("property graph property",,,"n of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,n}",{}) + type gt | (type,create_property_graph_tests,gt,create_property_graph_tests.gt) | (type,{create_property_graph_tests.gt},{}) + type gt[] | (type,create_property_graph_tests,_gt,create_property_graph_tests.gt[]) | (type,{create_property_graph_tests.gt[]},{}) + vertex v1 of property graph gt | ("property graph element",,,"v1 of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,v1}",{}) + vertex v2 of property graph gt | ("property graph element",,,"v2 of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,v2}",{}) +(52 rows) + \a\t SELECT pg_get_propgraphdef('g2'::regclass); CREATE PROPERTY GRAPH create_property_graph_tests.g2 diff --git a/src/test/regress/expected/event_trigger.out b/src/test/regress/expected/event_trigger.out index 065f586310f..ed8d5df397e 100644 --- a/src/test/regress/expected/event_trigger.out +++ b/src/test/regress/expected/event_trigger.out @@ -173,6 +173,23 @@ NOTICE: test_event_trigger: ddl_command_end CREATE USER MAPPING alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; NOTICE: test_event_trigger: ddl_command_end ALTER DEFAULT PRIVILEGES +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE TABLE t2x (i int PRIMARY KEY, j text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); +NOTICE: test_event_trigger: ddl_command_end CREATE PROPERTY GRAPH +DROP PROPERTY GRAPH gx; +NOTICE: test_event_trigger: ddl_command_end DROP PROPERTY GRAPH +DROP TABLE t1x, t2x; +NOTICE: test_event_trigger: ddl_command_end DROP TABLE -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; ERROR: permission denied to change owner of event trigger "regress_event_trigger" diff --git a/src/test/regress/expected/object_address.out b/src/test/regress/expected/object_address.out index 97227d67a54..5e53f0b092e 100644 --- a/src/test/regress/expected/object_address.out +++ b/src/test/regress/expected/object_address.out @@ -67,7 +67,9 @@ DECLARE BEGIN FOR objtype IN VALUES ('toast table'), ('index column'), ('sequence column'), ('toast table column'), ('view column'), ('materialized view column'), - ('property graph element'), ('property graph label'), ('property graph property') + ('property graph element'), ('property graph element label'), + ('property graph label'), ('property graph label property'), + ('property graph property') LOOP BEGIN PERFORM pg_get_object_address(objtype, '{one}', '{}'); @@ -84,7 +86,9 @@ WARNING: error for toast table column: unsupported object type "toast table col WARNING: error for view column: unsupported object type "view column" WARNING: error for materialized view column: unsupported object type "materialized view column" WARNING: error for property graph element: unsupported object type "property graph element" +WARNING: error for property graph element label: unrecognized object type "property graph element label" WARNING: error for property graph label: unsupported object type "property graph label" +WARNING: error for property graph label property: unrecognized object type "property graph label property" WARNING: error for property graph property: unsupported object type "property graph property" -- miscellaneous other errors select * from pg_get_object_address('operator of access method', '{btree,integer_ops,1}', '{int4,bool}'); @@ -593,7 +597,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace @@ -653,6 +659,8 @@ ORDER BY objects.classid, objects.objid, objects.objsubid; ("(""parameter ACL"",,,)")|("(""parameter ACL"",,)")|NULL ("(""property graph element"",,,)")|("(""property graph element"",,)")|NULL ("(""property graph label"",,,)")|("(""property graph label"",,)")|NULL +("(""property graph element label"",,,)")|("(""property graph element label"",,)")|NULL ("(""property graph property"",,,)")|("(""property graph property"",,)")|NULL +("(""property graph label property"",,,)")|("(""property graph label property"",,)")|NULL -- restore normal output mode \a\t diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..9608dd5c4af 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -298,6 +298,29 @@ SELECT (pg_identify_object(classid, objid, objsubid)).* refobjid = 'create_property_graph_tests.g2'::regclass ORDER BY 1, 2, 3, 4; +-- test object address functions with recursive dependency walk +-- covers all property graph object types including indirect dependents +SELECT * +FROM ( + WITH RECURSIVE deps (classid, objid, objsubid, refclassid, refobjid, refobjsubid) AS ( + SELECT classid, objid, objsubid, + refclassid, refobjid, refobjsubid + FROM pg_depend + WHERE refclassid = 'pg_class'::regclass AND + refobjid = 'create_property_graph_tests.gt'::regclass + UNION ALL + SELECT d.classid, d.objid, d.objsubid, + d.refclassid, d.refobjid, d.refobjsubid + FROM pg_depend d + JOIN deps dp ON d.refclassid = dp.classid AND d.refobjid = dp.objid AND d.refobjsubid = dp.objsubid + ) + SELECT pg_describe_object(classid, objid, objsubid) as obj, + pg_identify_object(classid, objid, objsubid) as ident, + pg_identify_object_as_address(classid, objid, objsubid) as addr + FROM deps +) s +ORDER BY obj COLLATE "C", ident::text COLLATE "C"; + \a\t SELECT pg_get_propgraphdef('g2'::regclass); SELECT pg_get_propgraphdef('g3'::regclass); diff --git a/src/test/regress/sql/event_trigger.sql b/src/test/regress/sql/event_trigger.sql index 32e9bb58c5e..271f443378b 100644 --- a/src/test/regress/sql/event_trigger.sql +++ b/src/test/regress/sql/event_trigger.sql @@ -143,6 +143,19 @@ create user mapping for regress_evt_user server useless_server; alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +CREATE TABLE t2x (i int PRIMARY KEY, j text); + +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); + +DROP PROPERTY GRAPH gx; +DROP TABLE t1x, t2x; + -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; diff --git a/src/test/regress/sql/object_address.sql b/src/test/regress/sql/object_address.sql index 1bbe9457c1c..27109d421c7 100644 --- a/src/test/regress/sql/object_address.sql +++ b/src/test/regress/sql/object_address.sql @@ -67,7 +67,9 @@ DECLARE BEGIN FOR objtype IN VALUES ('toast table'), ('index column'), ('sequence column'), ('toast table column'), ('view column'), ('materialized view column'), - ('property graph element'), ('property graph label'), ('property graph property') + ('property graph element'), ('property graph element label'), + ('property graph label'), ('property graph label property'), + ('property graph property') LOOP BEGIN PERFORM pg_get_object_address(objtype, '{one}', '{}'); @@ -282,7 +284,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace -- 2.34.1 --R84XrR4Hgw0dH3Ec-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v2] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-23 09:27 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-23 09:27 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing them to hit the default case and error out with "unsupported object class". During DROP PROPERTY GRAPH, this manifests when an event trigger is active, because pg_event_trigger_ddl_commands() calls these functions. The same code paths are also reachable via pg_identify_object() and pg_identify_object_as_address(). This commit adds the missing cases. Test coverage is added in object_address.sql for these two catalog types via the zero-OID test that exercises pg_identify_object() and pg_identify_object_as_address(). A test in event_trigger.sql verifies that DROP PROPERTY GRAPH works correctly when an event trigger is active. Author: Bertrand Drouvot <[email protected]> Reviewed-by: Michael Paquier <[email protected]> Reviewed-by: Ashutosh Bapat <[email protected]> Discussion: https://postgr.es/m/aej1DkLwhyZWmtxJ@bdtpg --- src/backend/catalog/objectaddress.c | 93 ++++++++++++++++++++ src/test/regress/expected/event_trigger.out | 17 ++++ src/test/regress/expected/object_address.out | 4 + src/test/regress/sql/event_trigger.sql | 13 +++ src/test/regress/sql/object_address.sql | 2 + 5 files changed, 129 insertions(+) 62.4% src/backend/catalog/ 25.6% src/test/regress/expected/ 11.8% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/event_trigger.out b/src/test/regress/expected/event_trigger.out index 065f586310f..ed8d5df397e 100644 --- a/src/test/regress/expected/event_trigger.out +++ b/src/test/regress/expected/event_trigger.out @@ -173,6 +173,23 @@ NOTICE: test_event_trigger: ddl_command_end CREATE USER MAPPING alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; NOTICE: test_event_trigger: ddl_command_end ALTER DEFAULT PRIVILEGES +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE TABLE t2x (i int PRIMARY KEY, j text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); +NOTICE: test_event_trigger: ddl_command_end CREATE PROPERTY GRAPH +DROP PROPERTY GRAPH gx; +NOTICE: test_event_trigger: ddl_command_end DROP PROPERTY GRAPH +DROP TABLE t1x, t2x; +NOTICE: test_event_trigger: ddl_command_end DROP TABLE -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; ERROR: permission denied to change owner of event trigger "regress_event_trigger" diff --git a/src/test/regress/expected/object_address.out b/src/test/regress/expected/object_address.out index 97227d67a54..729c3537f25 100644 --- a/src/test/regress/expected/object_address.out +++ b/src/test/regress/expected/object_address.out @@ -593,7 +593,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace @@ -653,6 +655,8 @@ ORDER BY objects.classid, objects.objid, objects.objsubid; ("(""parameter ACL"",,,)")|("(""parameter ACL"",,)")|NULL ("(""property graph element"",,,)")|("(""property graph element"",,)")|NULL ("(""property graph label"",,,)")|("(""property graph label"",,)")|NULL +("(""property graph element label"",,,)")|("(""property graph element label"",,)")|NULL ("(""property graph property"",,,)")|("(""property graph property"",,)")|NULL +("(""property graph label property"",,,)")|("(""property graph label property"",,)")|NULL -- restore normal output mode \a\t diff --git a/src/test/regress/sql/event_trigger.sql b/src/test/regress/sql/event_trigger.sql index 32e9bb58c5e..271f443378b 100644 --- a/src/test/regress/sql/event_trigger.sql +++ b/src/test/regress/sql/event_trigger.sql @@ -143,6 +143,19 @@ create user mapping for regress_evt_user server useless_server; alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +CREATE TABLE t2x (i int PRIMARY KEY, j text); + +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); + +DROP PROPERTY GRAPH gx; +DROP TABLE t1x, t2x; + -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; diff --git a/src/test/regress/sql/object_address.sql b/src/test/regress/sql/object_address.sql index 1bbe9457c1c..620dacf1045 100644 --- a/src/test/regress/sql/object_address.sql +++ b/src/test/regress/sql/object_address.sql @@ -282,7 +282,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace -- 2.34.1 --gtUR827Uq8d5gVsQ-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v3] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-23 09:27 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-23 09:27 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing them to hit the default case and error out with "unsupported object class". During DROP PROPERTY GRAPH, this manifests when an event trigger is active, because pg_event_trigger_ddl_commands() calls these functions. The same code paths are also reachable via pg_identify_object() and pg_identify_object_as_address(). This commit adds the missing cases. Test coverage is added in object_address.sql for these two catalog types and in create_property_graph.sql covering all property graph object types. A test in event_trigger.sql verifies that DROP PROPERTY GRAPH works correctly when an event trigger is active. Author: Bertrand Drouvot <[email protected]> Reviewed-by: Michael Paquier <[email protected]> Reviewed-by: Ashutosh Bapat <[email protected]> Discussion: https://postgr.es/m/aej1DkLwhyZWmtxJ@bdtpg --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 78 ++++++++++++++++ src/test/regress/expected/event_trigger.out | 17 ++++ src/test/regress/expected/object_address.out | 10 +- .../regress/sql/create_property_graph.sql | 23 +++++ src/test/regress/sql/event_trigger.sql | 13 +++ src/test/regress/sql/object_address.sql | 6 +- 7 files changed, 238 insertions(+), 2 deletions(-) 14.7% src/backend/catalog/ 75.5% src/test/regress/expected/ 9.7% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..eb9e17fb727 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -752,6 +752,84 @@ SELECT (pg_identify_object(classid, objid, objsubid)).* type | create_property_graph_tests | g2 | create_property_graph_tests.g2 (21 rows) +-- test object address functions with recursive dependency walk +-- covers all property graph object types including indirect dependents +SELECT * +FROM ( + WITH RECURSIVE deps (classid, objid, objsubid, refclassid, refobjid, refobjsubid) AS ( + SELECT classid, objid, objsubid, + refclassid, refobjid, refobjsubid + FROM pg_depend + WHERE refclassid = 'pg_class'::regclass AND + refobjid = 'create_property_graph_tests.gt'::regclass + UNION ALL + SELECT d.classid, d.objid, d.objsubid, + d.refclassid, d.refobjid, d.refobjsubid + FROM pg_depend d + JOIN deps dp ON d.refclassid = dp.classid AND d.refobjid = dp.objid AND d.refobjsubid = dp.objsubid + ) + SELECT pg_describe_object(classid, objid, objsubid) as obj, + pg_identify_object(classid, objid, objsubid) as ident, + pg_identify_object_as_address(classid, objid, objsubid) as addr + FROM deps +) s +ORDER BY obj COLLATE "C", ident::text COLLATE "C"; + obj | ident | addr +----------------------------------------------------------+----------------------------------------------------------------------------+---------------------------------------------------------------------------- + edge e of property graph gt | ("property graph element",,,"e of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,e}",{}) + edge e of property graph gt | ("property graph element",,,"e of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,e}",{}) + edge e of property graph gt | ("property graph element",,,"e of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of property graph gt | ("property graph label",,,"e of create_property_graph_tests.gt") | ("property graph label","{create_property_graph_tests,gt,e}",{}) + label v1 of property graph gt | ("property graph label",,,"v1 of create_property_graph_tests.gt") | ("property graph label","{create_property_graph_tests,gt,v1}",{}) + label v1 of vertex v1 of property graph gt | ("property graph element label",,,"v1 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v1}",{}) + label v1 of vertex v1 of property graph gt | ("property graph element label",,,"v1 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v1}",{}) + label v2 of property graph gt | ("property graph label",,,"v2 of create_property_graph_tests.gt") | ("property graph label","{create_property_graph_tests,gt,v2}",{}) + label v2 of vertex v2 of property graph gt | ("property graph element label",,,"v2 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v2}",{}) + label v2 of vertex v2 of property graph gt | ("property graph element label",,,"v2 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v2}",{}) + property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property a of property graph gt | ("property graph property",,,"a of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,a}",{}) + property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property b of property graph gt | ("property graph property",,,"b of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,b}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of property graph gt | ("property graph property",,,"c of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,c}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of property graph gt | ("property graph property",,,"k1 of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,k1}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of property graph gt | ("property graph property",,,"k2 of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,k2}",{}) + property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property m of property graph gt | ("property graph property",,,"m of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,m}",{}) + property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property n of property graph gt | ("property graph property",,,"n of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,n}",{}) + type gt | (type,create_property_graph_tests,gt,create_property_graph_tests.gt) | (type,{create_property_graph_tests.gt},{}) + type gt[] | (type,create_property_graph_tests,_gt,create_property_graph_tests.gt[]) | (type,{create_property_graph_tests.gt[]},{}) + vertex v1 of property graph gt | ("property graph element",,,"v1 of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,v1}",{}) + vertex v2 of property graph gt | ("property graph element",,,"v2 of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,v2}",{}) +(52 rows) + \a\t SELECT pg_get_propgraphdef('g2'::regclass); CREATE PROPERTY GRAPH create_property_graph_tests.g2 diff --git a/src/test/regress/expected/event_trigger.out b/src/test/regress/expected/event_trigger.out index 065f586310f..ed8d5df397e 100644 --- a/src/test/regress/expected/event_trigger.out +++ b/src/test/regress/expected/event_trigger.out @@ -173,6 +173,23 @@ NOTICE: test_event_trigger: ddl_command_end CREATE USER MAPPING alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; NOTICE: test_event_trigger: ddl_command_end ALTER DEFAULT PRIVILEGES +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE TABLE t2x (i int PRIMARY KEY, j text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); +NOTICE: test_event_trigger: ddl_command_end CREATE PROPERTY GRAPH +DROP PROPERTY GRAPH gx; +NOTICE: test_event_trigger: ddl_command_end DROP PROPERTY GRAPH +DROP TABLE t1x, t2x; +NOTICE: test_event_trigger: ddl_command_end DROP TABLE -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; ERROR: permission denied to change owner of event trigger "regress_event_trigger" diff --git a/src/test/regress/expected/object_address.out b/src/test/regress/expected/object_address.out index 97227d67a54..5e53f0b092e 100644 --- a/src/test/regress/expected/object_address.out +++ b/src/test/regress/expected/object_address.out @@ -67,7 +67,9 @@ DECLARE BEGIN FOR objtype IN VALUES ('toast table'), ('index column'), ('sequence column'), ('toast table column'), ('view column'), ('materialized view column'), - ('property graph element'), ('property graph label'), ('property graph property') + ('property graph element'), ('property graph element label'), + ('property graph label'), ('property graph label property'), + ('property graph property') LOOP BEGIN PERFORM pg_get_object_address(objtype, '{one}', '{}'); @@ -84,7 +86,9 @@ WARNING: error for toast table column: unsupported object type "toast table col WARNING: error for view column: unsupported object type "view column" WARNING: error for materialized view column: unsupported object type "materialized view column" WARNING: error for property graph element: unsupported object type "property graph element" +WARNING: error for property graph element label: unrecognized object type "property graph element label" WARNING: error for property graph label: unsupported object type "property graph label" +WARNING: error for property graph label property: unrecognized object type "property graph label property" WARNING: error for property graph property: unsupported object type "property graph property" -- miscellaneous other errors select * from pg_get_object_address('operator of access method', '{btree,integer_ops,1}', '{int4,bool}'); @@ -593,7 +597,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace @@ -653,6 +659,8 @@ ORDER BY objects.classid, objects.objid, objects.objsubid; ("(""parameter ACL"",,,)")|("(""parameter ACL"",,)")|NULL ("(""property graph element"",,,)")|("(""property graph element"",,)")|NULL ("(""property graph label"",,,)")|("(""property graph label"",,)")|NULL +("(""property graph element label"",,,)")|("(""property graph element label"",,)")|NULL ("(""property graph property"",,,)")|("(""property graph property"",,)")|NULL +("(""property graph label property"",,,)")|("(""property graph label property"",,)")|NULL -- restore normal output mode \a\t diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..9608dd5c4af 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -298,6 +298,29 @@ SELECT (pg_identify_object(classid, objid, objsubid)).* refobjid = 'create_property_graph_tests.g2'::regclass ORDER BY 1, 2, 3, 4; +-- test object address functions with recursive dependency walk +-- covers all property graph object types including indirect dependents +SELECT * +FROM ( + WITH RECURSIVE deps (classid, objid, objsubid, refclassid, refobjid, refobjsubid) AS ( + SELECT classid, objid, objsubid, + refclassid, refobjid, refobjsubid + FROM pg_depend + WHERE refclassid = 'pg_class'::regclass AND + refobjid = 'create_property_graph_tests.gt'::regclass + UNION ALL + SELECT d.classid, d.objid, d.objsubid, + d.refclassid, d.refobjid, d.refobjsubid + FROM pg_depend d + JOIN deps dp ON d.refclassid = dp.classid AND d.refobjid = dp.objid AND d.refobjsubid = dp.objsubid + ) + SELECT pg_describe_object(classid, objid, objsubid) as obj, + pg_identify_object(classid, objid, objsubid) as ident, + pg_identify_object_as_address(classid, objid, objsubid) as addr + FROM deps +) s +ORDER BY obj COLLATE "C", ident::text COLLATE "C"; + \a\t SELECT pg_get_propgraphdef('g2'::regclass); SELECT pg_get_propgraphdef('g3'::regclass); diff --git a/src/test/regress/sql/event_trigger.sql b/src/test/regress/sql/event_trigger.sql index 32e9bb58c5e..271f443378b 100644 --- a/src/test/regress/sql/event_trigger.sql +++ b/src/test/regress/sql/event_trigger.sql @@ -143,6 +143,19 @@ create user mapping for regress_evt_user server useless_server; alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +CREATE TABLE t2x (i int PRIMARY KEY, j text); + +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); + +DROP PROPERTY GRAPH gx; +DROP TABLE t1x, t2x; + -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; diff --git a/src/test/regress/sql/object_address.sql b/src/test/regress/sql/object_address.sql index 1bbe9457c1c..27109d421c7 100644 --- a/src/test/regress/sql/object_address.sql +++ b/src/test/regress/sql/object_address.sql @@ -67,7 +67,9 @@ DECLARE BEGIN FOR objtype IN VALUES ('toast table'), ('index column'), ('sequence column'), ('toast table column'), ('view column'), ('materialized view column'), - ('property graph element'), ('property graph label'), ('property graph property') + ('property graph element'), ('property graph element label'), + ('property graph label'), ('property graph label property'), + ('property graph property') LOOP BEGIN PERFORM pg_get_object_address(objtype, '{one}', '{}'); @@ -282,7 +284,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace -- 2.34.1 --R84XrR4Hgw0dH3Ec-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v3] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-23 09:27 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-23 09:27 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing them to hit the default case and error out with "unsupported object class". During DROP PROPERTY GRAPH, this manifests when an event trigger is active, because pg_event_trigger_ddl_commands() calls these functions. The same code paths are also reachable via pg_identify_object() and pg_identify_object_as_address(). This commit adds the missing cases. Test coverage is added in object_address.sql for these two catalog types and in create_property_graph.sql covering all property graph object types. A test in event_trigger.sql verifies that DROP PROPERTY GRAPH works correctly when an event trigger is active. Author: Bertrand Drouvot <[email protected]> Reviewed-by: Michael Paquier <[email protected]> Reviewed-by: Ashutosh Bapat <[email protected]> Discussion: https://postgr.es/m/aej1DkLwhyZWmtxJ@bdtpg --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 78 ++++++++++++++++ src/test/regress/expected/event_trigger.out | 17 ++++ src/test/regress/expected/object_address.out | 10 +- .../regress/sql/create_property_graph.sql | 23 +++++ src/test/regress/sql/event_trigger.sql | 13 +++ src/test/regress/sql/object_address.sql | 6 +- 7 files changed, 238 insertions(+), 2 deletions(-) 14.7% src/backend/catalog/ 75.5% src/test/regress/expected/ 9.7% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..eb9e17fb727 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -752,6 +752,84 @@ SELECT (pg_identify_object(classid, objid, objsubid)).* type | create_property_graph_tests | g2 | create_property_graph_tests.g2 (21 rows) +-- test object address functions with recursive dependency walk +-- covers all property graph object types including indirect dependents +SELECT * +FROM ( + WITH RECURSIVE deps (classid, objid, objsubid, refclassid, refobjid, refobjsubid) AS ( + SELECT classid, objid, objsubid, + refclassid, refobjid, refobjsubid + FROM pg_depend + WHERE refclassid = 'pg_class'::regclass AND + refobjid = 'create_property_graph_tests.gt'::regclass + UNION ALL + SELECT d.classid, d.objid, d.objsubid, + d.refclassid, d.refobjid, d.refobjsubid + FROM pg_depend d + JOIN deps dp ON d.refclassid = dp.classid AND d.refobjid = dp.objid AND d.refobjsubid = dp.objsubid + ) + SELECT pg_describe_object(classid, objid, objsubid) as obj, + pg_identify_object(classid, objid, objsubid) as ident, + pg_identify_object_as_address(classid, objid, objsubid) as addr + FROM deps +) s +ORDER BY obj COLLATE "C", ident::text COLLATE "C"; + obj | ident | addr +----------------------------------------------------------+----------------------------------------------------------------------------+---------------------------------------------------------------------------- + edge e of property graph gt | ("property graph element",,,"e of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,e}",{}) + edge e of property graph gt | ("property graph element",,,"e of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,e}",{}) + edge e of property graph gt | ("property graph element",,,"e of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of property graph gt | ("property graph label",,,"e of create_property_graph_tests.gt") | ("property graph label","{create_property_graph_tests,gt,e}",{}) + label v1 of property graph gt | ("property graph label",,,"v1 of create_property_graph_tests.gt") | ("property graph label","{create_property_graph_tests,gt,v1}",{}) + label v1 of vertex v1 of property graph gt | ("property graph element label",,,"v1 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v1}",{}) + label v1 of vertex v1 of property graph gt | ("property graph element label",,,"v1 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v1}",{}) + label v2 of property graph gt | ("property graph label",,,"v2 of create_property_graph_tests.gt") | ("property graph label","{create_property_graph_tests,gt,v2}",{}) + label v2 of vertex v2 of property graph gt | ("property graph element label",,,"v2 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v2}",{}) + label v2 of vertex v2 of property graph gt | ("property graph element label",,,"v2 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v2}",{}) + property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property a of property graph gt | ("property graph property",,,"a of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,a}",{}) + property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property b of property graph gt | ("property graph property",,,"b of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,b}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of property graph gt | ("property graph property",,,"c of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,c}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of property graph gt | ("property graph property",,,"k1 of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,k1}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of property graph gt | ("property graph property",,,"k2 of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,k2}",{}) + property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property m of property graph gt | ("property graph property",,,"m of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,m}",{}) + property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property n of property graph gt | ("property graph property",,,"n of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,n}",{}) + type gt | (type,create_property_graph_tests,gt,create_property_graph_tests.gt) | (type,{create_property_graph_tests.gt},{}) + type gt[] | (type,create_property_graph_tests,_gt,create_property_graph_tests.gt[]) | (type,{create_property_graph_tests.gt[]},{}) + vertex v1 of property graph gt | ("property graph element",,,"v1 of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,v1}",{}) + vertex v2 of property graph gt | ("property graph element",,,"v2 of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,v2}",{}) +(52 rows) + \a\t SELECT pg_get_propgraphdef('g2'::regclass); CREATE PROPERTY GRAPH create_property_graph_tests.g2 diff --git a/src/test/regress/expected/event_trigger.out b/src/test/regress/expected/event_trigger.out index 065f586310f..ed8d5df397e 100644 --- a/src/test/regress/expected/event_trigger.out +++ b/src/test/regress/expected/event_trigger.out @@ -173,6 +173,23 @@ NOTICE: test_event_trigger: ddl_command_end CREATE USER MAPPING alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; NOTICE: test_event_trigger: ddl_command_end ALTER DEFAULT PRIVILEGES +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE TABLE t2x (i int PRIMARY KEY, j text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); +NOTICE: test_event_trigger: ddl_command_end CREATE PROPERTY GRAPH +DROP PROPERTY GRAPH gx; +NOTICE: test_event_trigger: ddl_command_end DROP PROPERTY GRAPH +DROP TABLE t1x, t2x; +NOTICE: test_event_trigger: ddl_command_end DROP TABLE -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; ERROR: permission denied to change owner of event trigger "regress_event_trigger" diff --git a/src/test/regress/expected/object_address.out b/src/test/regress/expected/object_address.out index 97227d67a54..5e53f0b092e 100644 --- a/src/test/regress/expected/object_address.out +++ b/src/test/regress/expected/object_address.out @@ -67,7 +67,9 @@ DECLARE BEGIN FOR objtype IN VALUES ('toast table'), ('index column'), ('sequence column'), ('toast table column'), ('view column'), ('materialized view column'), - ('property graph element'), ('property graph label'), ('property graph property') + ('property graph element'), ('property graph element label'), + ('property graph label'), ('property graph label property'), + ('property graph property') LOOP BEGIN PERFORM pg_get_object_address(objtype, '{one}', '{}'); @@ -84,7 +86,9 @@ WARNING: error for toast table column: unsupported object type "toast table col WARNING: error for view column: unsupported object type "view column" WARNING: error for materialized view column: unsupported object type "materialized view column" WARNING: error for property graph element: unsupported object type "property graph element" +WARNING: error for property graph element label: unrecognized object type "property graph element label" WARNING: error for property graph label: unsupported object type "property graph label" +WARNING: error for property graph label property: unrecognized object type "property graph label property" WARNING: error for property graph property: unsupported object type "property graph property" -- miscellaneous other errors select * from pg_get_object_address('operator of access method', '{btree,integer_ops,1}', '{int4,bool}'); @@ -593,7 +597,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace @@ -653,6 +659,8 @@ ORDER BY objects.classid, objects.objid, objects.objsubid; ("(""parameter ACL"",,,)")|("(""parameter ACL"",,)")|NULL ("(""property graph element"",,,)")|("(""property graph element"",,)")|NULL ("(""property graph label"",,,)")|("(""property graph label"",,)")|NULL +("(""property graph element label"",,,)")|("(""property graph element label"",,)")|NULL ("(""property graph property"",,,)")|("(""property graph property"",,)")|NULL +("(""property graph label property"",,,)")|("(""property graph label property"",,)")|NULL -- restore normal output mode \a\t diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..9608dd5c4af 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -298,6 +298,29 @@ SELECT (pg_identify_object(classid, objid, objsubid)).* refobjid = 'create_property_graph_tests.g2'::regclass ORDER BY 1, 2, 3, 4; +-- test object address functions with recursive dependency walk +-- covers all property graph object types including indirect dependents +SELECT * +FROM ( + WITH RECURSIVE deps (classid, objid, objsubid, refclassid, refobjid, refobjsubid) AS ( + SELECT classid, objid, objsubid, + refclassid, refobjid, refobjsubid + FROM pg_depend + WHERE refclassid = 'pg_class'::regclass AND + refobjid = 'create_property_graph_tests.gt'::regclass + UNION ALL + SELECT d.classid, d.objid, d.objsubid, + d.refclassid, d.refobjid, d.refobjsubid + FROM pg_depend d + JOIN deps dp ON d.refclassid = dp.classid AND d.refobjid = dp.objid AND d.refobjsubid = dp.objsubid + ) + SELECT pg_describe_object(classid, objid, objsubid) as obj, + pg_identify_object(classid, objid, objsubid) as ident, + pg_identify_object_as_address(classid, objid, objsubid) as addr + FROM deps +) s +ORDER BY obj COLLATE "C", ident::text COLLATE "C"; + \a\t SELECT pg_get_propgraphdef('g2'::regclass); SELECT pg_get_propgraphdef('g3'::regclass); diff --git a/src/test/regress/sql/event_trigger.sql b/src/test/regress/sql/event_trigger.sql index 32e9bb58c5e..271f443378b 100644 --- a/src/test/regress/sql/event_trigger.sql +++ b/src/test/regress/sql/event_trigger.sql @@ -143,6 +143,19 @@ create user mapping for regress_evt_user server useless_server; alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +CREATE TABLE t2x (i int PRIMARY KEY, j text); + +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); + +DROP PROPERTY GRAPH gx; +DROP TABLE t1x, t2x; + -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; diff --git a/src/test/regress/sql/object_address.sql b/src/test/regress/sql/object_address.sql index 1bbe9457c1c..27109d421c7 100644 --- a/src/test/regress/sql/object_address.sql +++ b/src/test/regress/sql/object_address.sql @@ -67,7 +67,9 @@ DECLARE BEGIN FOR objtype IN VALUES ('toast table'), ('index column'), ('sequence column'), ('toast table column'), ('view column'), ('materialized view column'), - ('property graph element'), ('property graph label'), ('property graph property') + ('property graph element'), ('property graph element label'), + ('property graph label'), ('property graph label property'), + ('property graph property') LOOP BEGIN PERFORM pg_get_object_address(objtype, '{one}', '{}'); @@ -282,7 +284,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace -- 2.34.1 --R84XrR4Hgw0dH3Ec-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v3] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-23 09:27 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-23 09:27 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing them to hit the default case and error out with "unsupported object class". During DROP PROPERTY GRAPH, this manifests when an event trigger is active, because pg_event_trigger_ddl_commands() calls these functions. The same code paths are also reachable via pg_identify_object() and pg_identify_object_as_address(). This commit adds the missing cases. Test coverage is added in object_address.sql for these two catalog types and in create_property_graph.sql covering all property graph object types. A test in event_trigger.sql verifies that DROP PROPERTY GRAPH works correctly when an event trigger is active. Author: Bertrand Drouvot <[email protected]> Reviewed-by: Michael Paquier <[email protected]> Reviewed-by: Ashutosh Bapat <[email protected]> Discussion: https://postgr.es/m/aej1DkLwhyZWmtxJ@bdtpg --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 78 ++++++++++++++++ src/test/regress/expected/event_trigger.out | 17 ++++ src/test/regress/expected/object_address.out | 10 +- .../regress/sql/create_property_graph.sql | 23 +++++ src/test/regress/sql/event_trigger.sql | 13 +++ src/test/regress/sql/object_address.sql | 6 +- 7 files changed, 238 insertions(+), 2 deletions(-) 14.7% src/backend/catalog/ 75.5% src/test/regress/expected/ 9.7% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..eb9e17fb727 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -752,6 +752,84 @@ SELECT (pg_identify_object(classid, objid, objsubid)).* type | create_property_graph_tests | g2 | create_property_graph_tests.g2 (21 rows) +-- test object address functions with recursive dependency walk +-- covers all property graph object types including indirect dependents +SELECT * +FROM ( + WITH RECURSIVE deps (classid, objid, objsubid, refclassid, refobjid, refobjsubid) AS ( + SELECT classid, objid, objsubid, + refclassid, refobjid, refobjsubid + FROM pg_depend + WHERE refclassid = 'pg_class'::regclass AND + refobjid = 'create_property_graph_tests.gt'::regclass + UNION ALL + SELECT d.classid, d.objid, d.objsubid, + d.refclassid, d.refobjid, d.refobjsubid + FROM pg_depend d + JOIN deps dp ON d.refclassid = dp.classid AND d.refobjid = dp.objid AND d.refobjsubid = dp.objsubid + ) + SELECT pg_describe_object(classid, objid, objsubid) as obj, + pg_identify_object(classid, objid, objsubid) as ident, + pg_identify_object_as_address(classid, objid, objsubid) as addr + FROM deps +) s +ORDER BY obj COLLATE "C", ident::text COLLATE "C"; + obj | ident | addr +----------------------------------------------------------+----------------------------------------------------------------------------+---------------------------------------------------------------------------- + edge e of property graph gt | ("property graph element",,,"e of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,e}",{}) + edge e of property graph gt | ("property graph element",,,"e of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,e}",{}) + edge e of property graph gt | ("property graph element",,,"e of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of property graph gt | ("property graph label",,,"e of create_property_graph_tests.gt") | ("property graph label","{create_property_graph_tests,gt,e}",{}) + label v1 of property graph gt | ("property graph label",,,"v1 of create_property_graph_tests.gt") | ("property graph label","{create_property_graph_tests,gt,v1}",{}) + label v1 of vertex v1 of property graph gt | ("property graph element label",,,"v1 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v1}",{}) + label v1 of vertex v1 of property graph gt | ("property graph element label",,,"v1 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v1}",{}) + label v2 of property graph gt | ("property graph label",,,"v2 of create_property_graph_tests.gt") | ("property graph label","{create_property_graph_tests,gt,v2}",{}) + label v2 of vertex v2 of property graph gt | ("property graph element label",,,"v2 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v2}",{}) + label v2 of vertex v2 of property graph gt | ("property graph element label",,,"v2 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v2}",{}) + property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property a of property graph gt | ("property graph property",,,"a of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,a}",{}) + property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property b of property graph gt | ("property graph property",,,"b of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,b}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of property graph gt | ("property graph property",,,"c of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,c}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of property graph gt | ("property graph property",,,"k1 of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,k1}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of property graph gt | ("property graph property",,,"k2 of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,k2}",{}) + property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property m of property graph gt | ("property graph property",,,"m of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,m}",{}) + property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property n of property graph gt | ("property graph property",,,"n of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,n}",{}) + type gt | (type,create_property_graph_tests,gt,create_property_graph_tests.gt) | (type,{create_property_graph_tests.gt},{}) + type gt[] | (type,create_property_graph_tests,_gt,create_property_graph_tests.gt[]) | (type,{create_property_graph_tests.gt[]},{}) + vertex v1 of property graph gt | ("property graph element",,,"v1 of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,v1}",{}) + vertex v2 of property graph gt | ("property graph element",,,"v2 of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,v2}",{}) +(52 rows) + \a\t SELECT pg_get_propgraphdef('g2'::regclass); CREATE PROPERTY GRAPH create_property_graph_tests.g2 diff --git a/src/test/regress/expected/event_trigger.out b/src/test/regress/expected/event_trigger.out index 065f586310f..ed8d5df397e 100644 --- a/src/test/regress/expected/event_trigger.out +++ b/src/test/regress/expected/event_trigger.out @@ -173,6 +173,23 @@ NOTICE: test_event_trigger: ddl_command_end CREATE USER MAPPING alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; NOTICE: test_event_trigger: ddl_command_end ALTER DEFAULT PRIVILEGES +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE TABLE t2x (i int PRIMARY KEY, j text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); +NOTICE: test_event_trigger: ddl_command_end CREATE PROPERTY GRAPH +DROP PROPERTY GRAPH gx; +NOTICE: test_event_trigger: ddl_command_end DROP PROPERTY GRAPH +DROP TABLE t1x, t2x; +NOTICE: test_event_trigger: ddl_command_end DROP TABLE -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; ERROR: permission denied to change owner of event trigger "regress_event_trigger" diff --git a/src/test/regress/expected/object_address.out b/src/test/regress/expected/object_address.out index 97227d67a54..5e53f0b092e 100644 --- a/src/test/regress/expected/object_address.out +++ b/src/test/regress/expected/object_address.out @@ -67,7 +67,9 @@ DECLARE BEGIN FOR objtype IN VALUES ('toast table'), ('index column'), ('sequence column'), ('toast table column'), ('view column'), ('materialized view column'), - ('property graph element'), ('property graph label'), ('property graph property') + ('property graph element'), ('property graph element label'), + ('property graph label'), ('property graph label property'), + ('property graph property') LOOP BEGIN PERFORM pg_get_object_address(objtype, '{one}', '{}'); @@ -84,7 +86,9 @@ WARNING: error for toast table column: unsupported object type "toast table col WARNING: error for view column: unsupported object type "view column" WARNING: error for materialized view column: unsupported object type "materialized view column" WARNING: error for property graph element: unsupported object type "property graph element" +WARNING: error for property graph element label: unrecognized object type "property graph element label" WARNING: error for property graph label: unsupported object type "property graph label" +WARNING: error for property graph label property: unrecognized object type "property graph label property" WARNING: error for property graph property: unsupported object type "property graph property" -- miscellaneous other errors select * from pg_get_object_address('operator of access method', '{btree,integer_ops,1}', '{int4,bool}'); @@ -593,7 +597,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace @@ -653,6 +659,8 @@ ORDER BY objects.classid, objects.objid, objects.objsubid; ("(""parameter ACL"",,,)")|("(""parameter ACL"",,)")|NULL ("(""property graph element"",,,)")|("(""property graph element"",,)")|NULL ("(""property graph label"",,,)")|("(""property graph label"",,)")|NULL +("(""property graph element label"",,,)")|("(""property graph element label"",,)")|NULL ("(""property graph property"",,,)")|("(""property graph property"",,)")|NULL +("(""property graph label property"",,,)")|("(""property graph label property"",,)")|NULL -- restore normal output mode \a\t diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..9608dd5c4af 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -298,6 +298,29 @@ SELECT (pg_identify_object(classid, objid, objsubid)).* refobjid = 'create_property_graph_tests.g2'::regclass ORDER BY 1, 2, 3, 4; +-- test object address functions with recursive dependency walk +-- covers all property graph object types including indirect dependents +SELECT * +FROM ( + WITH RECURSIVE deps (classid, objid, objsubid, refclassid, refobjid, refobjsubid) AS ( + SELECT classid, objid, objsubid, + refclassid, refobjid, refobjsubid + FROM pg_depend + WHERE refclassid = 'pg_class'::regclass AND + refobjid = 'create_property_graph_tests.gt'::regclass + UNION ALL + SELECT d.classid, d.objid, d.objsubid, + d.refclassid, d.refobjid, d.refobjsubid + FROM pg_depend d + JOIN deps dp ON d.refclassid = dp.classid AND d.refobjid = dp.objid AND d.refobjsubid = dp.objsubid + ) + SELECT pg_describe_object(classid, objid, objsubid) as obj, + pg_identify_object(classid, objid, objsubid) as ident, + pg_identify_object_as_address(classid, objid, objsubid) as addr + FROM deps +) s +ORDER BY obj COLLATE "C", ident::text COLLATE "C"; + \a\t SELECT pg_get_propgraphdef('g2'::regclass); SELECT pg_get_propgraphdef('g3'::regclass); diff --git a/src/test/regress/sql/event_trigger.sql b/src/test/regress/sql/event_trigger.sql index 32e9bb58c5e..271f443378b 100644 --- a/src/test/regress/sql/event_trigger.sql +++ b/src/test/regress/sql/event_trigger.sql @@ -143,6 +143,19 @@ create user mapping for regress_evt_user server useless_server; alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +CREATE TABLE t2x (i int PRIMARY KEY, j text); + +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); + +DROP PROPERTY GRAPH gx; +DROP TABLE t1x, t2x; + -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; diff --git a/src/test/regress/sql/object_address.sql b/src/test/regress/sql/object_address.sql index 1bbe9457c1c..27109d421c7 100644 --- a/src/test/regress/sql/object_address.sql +++ b/src/test/regress/sql/object_address.sql @@ -67,7 +67,9 @@ DECLARE BEGIN FOR objtype IN VALUES ('toast table'), ('index column'), ('sequence column'), ('toast table column'), ('view column'), ('materialized view column'), - ('property graph element'), ('property graph label'), ('property graph property') + ('property graph element'), ('property graph element label'), + ('property graph label'), ('property graph label property'), + ('property graph property') LOOP BEGIN PERFORM pg_get_object_address(objtype, '{one}', '{}'); @@ -282,7 +284,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace -- 2.34.1 --R84XrR4Hgw0dH3Ec-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v2] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-23 09:27 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-23 09:27 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing them to hit the default case and error out with "unsupported object class". During DROP PROPERTY GRAPH, this manifests when an event trigger is active, because pg_event_trigger_ddl_commands() calls these functions. The same code paths are also reachable via pg_identify_object() and pg_identify_object_as_address(). This commit adds the missing cases. Test coverage is added in object_address.sql for these two catalog types via the zero-OID test that exercises pg_identify_object() and pg_identify_object_as_address(). A test in event_trigger.sql verifies that DROP PROPERTY GRAPH works correctly when an event trigger is active. Author: Bertrand Drouvot <[email protected]> Reviewed-by: Michael Paquier <[email protected]> Reviewed-by: Ashutosh Bapat <[email protected]> Discussion: https://postgr.es/m/aej1DkLwhyZWmtxJ@bdtpg --- src/backend/catalog/objectaddress.c | 93 ++++++++++++++++++++ src/test/regress/expected/event_trigger.out | 17 ++++ src/test/regress/expected/object_address.out | 4 + src/test/regress/sql/event_trigger.sql | 13 +++ src/test/regress/sql/object_address.sql | 2 + 5 files changed, 129 insertions(+) 62.4% src/backend/catalog/ 25.6% src/test/regress/expected/ 11.8% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/event_trigger.out b/src/test/regress/expected/event_trigger.out index 065f586310f..ed8d5df397e 100644 --- a/src/test/regress/expected/event_trigger.out +++ b/src/test/regress/expected/event_trigger.out @@ -173,6 +173,23 @@ NOTICE: test_event_trigger: ddl_command_end CREATE USER MAPPING alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; NOTICE: test_event_trigger: ddl_command_end ALTER DEFAULT PRIVILEGES +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE TABLE t2x (i int PRIMARY KEY, j text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); +NOTICE: test_event_trigger: ddl_command_end CREATE PROPERTY GRAPH +DROP PROPERTY GRAPH gx; +NOTICE: test_event_trigger: ddl_command_end DROP PROPERTY GRAPH +DROP TABLE t1x, t2x; +NOTICE: test_event_trigger: ddl_command_end DROP TABLE -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; ERROR: permission denied to change owner of event trigger "regress_event_trigger" diff --git a/src/test/regress/expected/object_address.out b/src/test/regress/expected/object_address.out index 97227d67a54..729c3537f25 100644 --- a/src/test/regress/expected/object_address.out +++ b/src/test/regress/expected/object_address.out @@ -593,7 +593,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace @@ -653,6 +655,8 @@ ORDER BY objects.classid, objects.objid, objects.objsubid; ("(""parameter ACL"",,,)")|("(""parameter ACL"",,)")|NULL ("(""property graph element"",,,)")|("(""property graph element"",,)")|NULL ("(""property graph label"",,,)")|("(""property graph label"",,)")|NULL +("(""property graph element label"",,,)")|("(""property graph element label"",,)")|NULL ("(""property graph property"",,,)")|("(""property graph property"",,)")|NULL +("(""property graph label property"",,,)")|("(""property graph label property"",,)")|NULL -- restore normal output mode \a\t diff --git a/src/test/regress/sql/event_trigger.sql b/src/test/regress/sql/event_trigger.sql index 32e9bb58c5e..271f443378b 100644 --- a/src/test/regress/sql/event_trigger.sql +++ b/src/test/regress/sql/event_trigger.sql @@ -143,6 +143,19 @@ create user mapping for regress_evt_user server useless_server; alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +CREATE TABLE t2x (i int PRIMARY KEY, j text); + +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); + +DROP PROPERTY GRAPH gx; +DROP TABLE t1x, t2x; + -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; diff --git a/src/test/regress/sql/object_address.sql b/src/test/regress/sql/object_address.sql index 1bbe9457c1c..620dacf1045 100644 --- a/src/test/regress/sql/object_address.sql +++ b/src/test/regress/sql/object_address.sql @@ -282,7 +282,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace -- 2.34.1 --gtUR827Uq8d5gVsQ-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v3] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-23 09:27 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-23 09:27 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing them to hit the default case and error out with "unsupported object class". During DROP PROPERTY GRAPH, this manifests when an event trigger is active, because pg_event_trigger_ddl_commands() calls these functions. The same code paths are also reachable via pg_identify_object() and pg_identify_object_as_address(). This commit adds the missing cases. Test coverage is added in object_address.sql for these two catalog types and in create_property_graph.sql covering all property graph object types. A test in event_trigger.sql verifies that DROP PROPERTY GRAPH works correctly when an event trigger is active. Author: Bertrand Drouvot <[email protected]> Reviewed-by: Michael Paquier <[email protected]> Reviewed-by: Ashutosh Bapat <[email protected]> Discussion: https://postgr.es/m/aej1DkLwhyZWmtxJ@bdtpg --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 78 ++++++++++++++++ src/test/regress/expected/event_trigger.out | 17 ++++ src/test/regress/expected/object_address.out | 10 +- .../regress/sql/create_property_graph.sql | 23 +++++ src/test/regress/sql/event_trigger.sql | 13 +++ src/test/regress/sql/object_address.sql | 6 +- 7 files changed, 238 insertions(+), 2 deletions(-) 14.7% src/backend/catalog/ 75.5% src/test/regress/expected/ 9.7% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..eb9e17fb727 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -752,6 +752,84 @@ SELECT (pg_identify_object(classid, objid, objsubid)).* type | create_property_graph_tests | g2 | create_property_graph_tests.g2 (21 rows) +-- test object address functions with recursive dependency walk +-- covers all property graph object types including indirect dependents +SELECT * +FROM ( + WITH RECURSIVE deps (classid, objid, objsubid, refclassid, refobjid, refobjsubid) AS ( + SELECT classid, objid, objsubid, + refclassid, refobjid, refobjsubid + FROM pg_depend + WHERE refclassid = 'pg_class'::regclass AND + refobjid = 'create_property_graph_tests.gt'::regclass + UNION ALL + SELECT d.classid, d.objid, d.objsubid, + d.refclassid, d.refobjid, d.refobjsubid + FROM pg_depend d + JOIN deps dp ON d.refclassid = dp.classid AND d.refobjid = dp.objid AND d.refobjsubid = dp.objsubid + ) + SELECT pg_describe_object(classid, objid, objsubid) as obj, + pg_identify_object(classid, objid, objsubid) as ident, + pg_identify_object_as_address(classid, objid, objsubid) as addr + FROM deps +) s +ORDER BY obj COLLATE "C", ident::text COLLATE "C"; + obj | ident | addr +----------------------------------------------------------+----------------------------------------------------------------------------+---------------------------------------------------------------------------- + edge e of property graph gt | ("property graph element",,,"e of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,e}",{}) + edge e of property graph gt | ("property graph element",,,"e of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,e}",{}) + edge e of property graph gt | ("property graph element",,,"e of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of property graph gt | ("property graph label",,,"e of create_property_graph_tests.gt") | ("property graph label","{create_property_graph_tests,gt,e}",{}) + label v1 of property graph gt | ("property graph label",,,"v1 of create_property_graph_tests.gt") | ("property graph label","{create_property_graph_tests,gt,v1}",{}) + label v1 of vertex v1 of property graph gt | ("property graph element label",,,"v1 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v1}",{}) + label v1 of vertex v1 of property graph gt | ("property graph element label",,,"v1 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v1}",{}) + label v2 of property graph gt | ("property graph label",,,"v2 of create_property_graph_tests.gt") | ("property graph label","{create_property_graph_tests,gt,v2}",{}) + label v2 of vertex v2 of property graph gt | ("property graph element label",,,"v2 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v2}",{}) + label v2 of vertex v2 of property graph gt | ("property graph element label",,,"v2 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v2}",{}) + property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property a of property graph gt | ("property graph property",,,"a of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,a}",{}) + property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property b of property graph gt | ("property graph property",,,"b of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,b}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of property graph gt | ("property graph property",,,"c of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,c}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of property graph gt | ("property graph property",,,"k1 of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,k1}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of property graph gt | ("property graph property",,,"k2 of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,k2}",{}) + property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property m of property graph gt | ("property graph property",,,"m of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,m}",{}) + property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property n of property graph gt | ("property graph property",,,"n of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,n}",{}) + type gt | (type,create_property_graph_tests,gt,create_property_graph_tests.gt) | (type,{create_property_graph_tests.gt},{}) + type gt[] | (type,create_property_graph_tests,_gt,create_property_graph_tests.gt[]) | (type,{create_property_graph_tests.gt[]},{}) + vertex v1 of property graph gt | ("property graph element",,,"v1 of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,v1}",{}) + vertex v2 of property graph gt | ("property graph element",,,"v2 of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,v2}",{}) +(52 rows) + \a\t SELECT pg_get_propgraphdef('g2'::regclass); CREATE PROPERTY GRAPH create_property_graph_tests.g2 diff --git a/src/test/regress/expected/event_trigger.out b/src/test/regress/expected/event_trigger.out index 065f586310f..ed8d5df397e 100644 --- a/src/test/regress/expected/event_trigger.out +++ b/src/test/regress/expected/event_trigger.out @@ -173,6 +173,23 @@ NOTICE: test_event_trigger: ddl_command_end CREATE USER MAPPING alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; NOTICE: test_event_trigger: ddl_command_end ALTER DEFAULT PRIVILEGES +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE TABLE t2x (i int PRIMARY KEY, j text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); +NOTICE: test_event_trigger: ddl_command_end CREATE PROPERTY GRAPH +DROP PROPERTY GRAPH gx; +NOTICE: test_event_trigger: ddl_command_end DROP PROPERTY GRAPH +DROP TABLE t1x, t2x; +NOTICE: test_event_trigger: ddl_command_end DROP TABLE -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; ERROR: permission denied to change owner of event trigger "regress_event_trigger" diff --git a/src/test/regress/expected/object_address.out b/src/test/regress/expected/object_address.out index 97227d67a54..5e53f0b092e 100644 --- a/src/test/regress/expected/object_address.out +++ b/src/test/regress/expected/object_address.out @@ -67,7 +67,9 @@ DECLARE BEGIN FOR objtype IN VALUES ('toast table'), ('index column'), ('sequence column'), ('toast table column'), ('view column'), ('materialized view column'), - ('property graph element'), ('property graph label'), ('property graph property') + ('property graph element'), ('property graph element label'), + ('property graph label'), ('property graph label property'), + ('property graph property') LOOP BEGIN PERFORM pg_get_object_address(objtype, '{one}', '{}'); @@ -84,7 +86,9 @@ WARNING: error for toast table column: unsupported object type "toast table col WARNING: error for view column: unsupported object type "view column" WARNING: error for materialized view column: unsupported object type "materialized view column" WARNING: error for property graph element: unsupported object type "property graph element" +WARNING: error for property graph element label: unrecognized object type "property graph element label" WARNING: error for property graph label: unsupported object type "property graph label" +WARNING: error for property graph label property: unrecognized object type "property graph label property" WARNING: error for property graph property: unsupported object type "property graph property" -- miscellaneous other errors select * from pg_get_object_address('operator of access method', '{btree,integer_ops,1}', '{int4,bool}'); @@ -593,7 +597,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace @@ -653,6 +659,8 @@ ORDER BY objects.classid, objects.objid, objects.objsubid; ("(""parameter ACL"",,,)")|("(""parameter ACL"",,)")|NULL ("(""property graph element"",,,)")|("(""property graph element"",,)")|NULL ("(""property graph label"",,,)")|("(""property graph label"",,)")|NULL +("(""property graph element label"",,,)")|("(""property graph element label"",,)")|NULL ("(""property graph property"",,,)")|("(""property graph property"",,)")|NULL +("(""property graph label property"",,,)")|("(""property graph label property"",,)")|NULL -- restore normal output mode \a\t diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..9608dd5c4af 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -298,6 +298,29 @@ SELECT (pg_identify_object(classid, objid, objsubid)).* refobjid = 'create_property_graph_tests.g2'::regclass ORDER BY 1, 2, 3, 4; +-- test object address functions with recursive dependency walk +-- covers all property graph object types including indirect dependents +SELECT * +FROM ( + WITH RECURSIVE deps (classid, objid, objsubid, refclassid, refobjid, refobjsubid) AS ( + SELECT classid, objid, objsubid, + refclassid, refobjid, refobjsubid + FROM pg_depend + WHERE refclassid = 'pg_class'::regclass AND + refobjid = 'create_property_graph_tests.gt'::regclass + UNION ALL + SELECT d.classid, d.objid, d.objsubid, + d.refclassid, d.refobjid, d.refobjsubid + FROM pg_depend d + JOIN deps dp ON d.refclassid = dp.classid AND d.refobjid = dp.objid AND d.refobjsubid = dp.objsubid + ) + SELECT pg_describe_object(classid, objid, objsubid) as obj, + pg_identify_object(classid, objid, objsubid) as ident, + pg_identify_object_as_address(classid, objid, objsubid) as addr + FROM deps +) s +ORDER BY obj COLLATE "C", ident::text COLLATE "C"; + \a\t SELECT pg_get_propgraphdef('g2'::regclass); SELECT pg_get_propgraphdef('g3'::regclass); diff --git a/src/test/regress/sql/event_trigger.sql b/src/test/regress/sql/event_trigger.sql index 32e9bb58c5e..271f443378b 100644 --- a/src/test/regress/sql/event_trigger.sql +++ b/src/test/regress/sql/event_trigger.sql @@ -143,6 +143,19 @@ create user mapping for regress_evt_user server useless_server; alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +CREATE TABLE t2x (i int PRIMARY KEY, j text); + +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); + +DROP PROPERTY GRAPH gx; +DROP TABLE t1x, t2x; + -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; diff --git a/src/test/regress/sql/object_address.sql b/src/test/regress/sql/object_address.sql index 1bbe9457c1c..27109d421c7 100644 --- a/src/test/regress/sql/object_address.sql +++ b/src/test/regress/sql/object_address.sql @@ -67,7 +67,9 @@ DECLARE BEGIN FOR objtype IN VALUES ('toast table'), ('index column'), ('sequence column'), ('toast table column'), ('view column'), ('materialized view column'), - ('property graph element'), ('property graph label'), ('property graph property') + ('property graph element'), ('property graph element label'), + ('property graph label'), ('property graph label property'), + ('property graph property') LOOP BEGIN PERFORM pg_get_object_address(objtype, '{one}', '{}'); @@ -282,7 +284,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace -- 2.34.1 --R84XrR4Hgw0dH3Ec-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
* [PATCH v3] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-23 09:27 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2390+ messages in thread From: Bertrand Drouvot @ 2026-04-23 09:27 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing them to hit the default case and error out with "unsupported object class". During DROP PROPERTY GRAPH, this manifests when an event trigger is active, because pg_event_trigger_ddl_commands() calls these functions. The same code paths are also reachable via pg_identify_object() and pg_identify_object_as_address(). This commit adds the missing cases. Test coverage is added in object_address.sql for these two catalog types and in create_property_graph.sql covering all property graph object types. A test in event_trigger.sql verifies that DROP PROPERTY GRAPH works correctly when an event trigger is active. Author: Bertrand Drouvot <[email protected]> Reviewed-by: Michael Paquier <[email protected]> Reviewed-by: Ashutosh Bapat <[email protected]> Discussion: https://postgr.es/m/aej1DkLwhyZWmtxJ@bdtpg --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 78 ++++++++++++++++ src/test/regress/expected/event_trigger.out | 17 ++++ src/test/regress/expected/object_address.out | 10 +- .../regress/sql/create_property_graph.sql | 23 +++++ src/test/regress/sql/event_trigger.sql | 13 +++ src/test/regress/sql/object_address.sql | 6 +- 7 files changed, 238 insertions(+), 2 deletions(-) 14.7% src/backend/catalog/ 75.5% src/test/regress/expected/ 9.7% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..eb9e17fb727 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -752,6 +752,84 @@ SELECT (pg_identify_object(classid, objid, objsubid)).* type | create_property_graph_tests | g2 | create_property_graph_tests.g2 (21 rows) +-- test object address functions with recursive dependency walk +-- covers all property graph object types including indirect dependents +SELECT * +FROM ( + WITH RECURSIVE deps (classid, objid, objsubid, refclassid, refobjid, refobjsubid) AS ( + SELECT classid, objid, objsubid, + refclassid, refobjid, refobjsubid + FROM pg_depend + WHERE refclassid = 'pg_class'::regclass AND + refobjid = 'create_property_graph_tests.gt'::regclass + UNION ALL + SELECT d.classid, d.objid, d.objsubid, + d.refclassid, d.refobjid, d.refobjsubid + FROM pg_depend d + JOIN deps dp ON d.refclassid = dp.classid AND d.refobjid = dp.objid AND d.refobjsubid = dp.objsubid + ) + SELECT pg_describe_object(classid, objid, objsubid) as obj, + pg_identify_object(classid, objid, objsubid) as ident, + pg_identify_object_as_address(classid, objid, objsubid) as addr + FROM deps +) s +ORDER BY obj COLLATE "C", ident::text COLLATE "C"; + obj | ident | addr +----------------------------------------------------------+----------------------------------------------------------------------------+---------------------------------------------------------------------------- + edge e of property graph gt | ("property graph element",,,"e of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,e}",{}) + edge e of property graph gt | ("property graph element",,,"e of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,e}",{}) + edge e of property graph gt | ("property graph element",,,"e of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of property graph gt | ("property graph label",,,"e of create_property_graph_tests.gt") | ("property graph label","{create_property_graph_tests,gt,e}",{}) + label v1 of property graph gt | ("property graph label",,,"v1 of create_property_graph_tests.gt") | ("property graph label","{create_property_graph_tests,gt,v1}",{}) + label v1 of vertex v1 of property graph gt | ("property graph element label",,,"v1 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v1}",{}) + label v1 of vertex v1 of property graph gt | ("property graph element label",,,"v1 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v1}",{}) + label v2 of property graph gt | ("property graph label",,,"v2 of create_property_graph_tests.gt") | ("property graph label","{create_property_graph_tests,gt,v2}",{}) + label v2 of vertex v2 of property graph gt | ("property graph element label",,,"v2 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v2}",{}) + label v2 of vertex v2 of property graph gt | ("property graph element label",,,"v2 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v2}",{}) + property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property a of property graph gt | ("property graph property",,,"a of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,a}",{}) + property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property b of property graph gt | ("property graph property",,,"b of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,b}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of property graph gt | ("property graph property",,,"c of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,c}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of property graph gt | ("property graph property",,,"k1 of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,k1}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of property graph gt | ("property graph property",,,"k2 of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,k2}",{}) + property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property m of property graph gt | ("property graph property",,,"m of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,m}",{}) + property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property n of property graph gt | ("property graph property",,,"n of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,n}",{}) + type gt | (type,create_property_graph_tests,gt,create_property_graph_tests.gt) | (type,{create_property_graph_tests.gt},{}) + type gt[] | (type,create_property_graph_tests,_gt,create_property_graph_tests.gt[]) | (type,{create_property_graph_tests.gt[]},{}) + vertex v1 of property graph gt | ("property graph element",,,"v1 of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,v1}",{}) + vertex v2 of property graph gt | ("property graph element",,,"v2 of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,v2}",{}) +(52 rows) + \a\t SELECT pg_get_propgraphdef('g2'::regclass); CREATE PROPERTY GRAPH create_property_graph_tests.g2 diff --git a/src/test/regress/expected/event_trigger.out b/src/test/regress/expected/event_trigger.out index 065f586310f..ed8d5df397e 100644 --- a/src/test/regress/expected/event_trigger.out +++ b/src/test/regress/expected/event_trigger.out @@ -173,6 +173,23 @@ NOTICE: test_event_trigger: ddl_command_end CREATE USER MAPPING alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; NOTICE: test_event_trigger: ddl_command_end ALTER DEFAULT PRIVILEGES +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE TABLE t2x (i int PRIMARY KEY, j text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); +NOTICE: test_event_trigger: ddl_command_end CREATE PROPERTY GRAPH +DROP PROPERTY GRAPH gx; +NOTICE: test_event_trigger: ddl_command_end DROP PROPERTY GRAPH +DROP TABLE t1x, t2x; +NOTICE: test_event_trigger: ddl_command_end DROP TABLE -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; ERROR: permission denied to change owner of event trigger "regress_event_trigger" diff --git a/src/test/regress/expected/object_address.out b/src/test/regress/expected/object_address.out index 97227d67a54..5e53f0b092e 100644 --- a/src/test/regress/expected/object_address.out +++ b/src/test/regress/expected/object_address.out @@ -67,7 +67,9 @@ DECLARE BEGIN FOR objtype IN VALUES ('toast table'), ('index column'), ('sequence column'), ('toast table column'), ('view column'), ('materialized view column'), - ('property graph element'), ('property graph label'), ('property graph property') + ('property graph element'), ('property graph element label'), + ('property graph label'), ('property graph label property'), + ('property graph property') LOOP BEGIN PERFORM pg_get_object_address(objtype, '{one}', '{}'); @@ -84,7 +86,9 @@ WARNING: error for toast table column: unsupported object type "toast table col WARNING: error for view column: unsupported object type "view column" WARNING: error for materialized view column: unsupported object type "materialized view column" WARNING: error for property graph element: unsupported object type "property graph element" +WARNING: error for property graph element label: unrecognized object type "property graph element label" WARNING: error for property graph label: unsupported object type "property graph label" +WARNING: error for property graph label property: unrecognized object type "property graph label property" WARNING: error for property graph property: unsupported object type "property graph property" -- miscellaneous other errors select * from pg_get_object_address('operator of access method', '{btree,integer_ops,1}', '{int4,bool}'); @@ -593,7 +597,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace @@ -653,6 +659,8 @@ ORDER BY objects.classid, objects.objid, objects.objsubid; ("(""parameter ACL"",,,)")|("(""parameter ACL"",,)")|NULL ("(""property graph element"",,,)")|("(""property graph element"",,)")|NULL ("(""property graph label"",,,)")|("(""property graph label"",,)")|NULL +("(""property graph element label"",,,)")|("(""property graph element label"",,)")|NULL ("(""property graph property"",,,)")|("(""property graph property"",,)")|NULL +("(""property graph label property"",,,)")|("(""property graph label property"",,)")|NULL -- restore normal output mode \a\t diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..9608dd5c4af 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -298,6 +298,29 @@ SELECT (pg_identify_object(classid, objid, objsubid)).* refobjid = 'create_property_graph_tests.g2'::regclass ORDER BY 1, 2, 3, 4; +-- test object address functions with recursive dependency walk +-- covers all property graph object types including indirect dependents +SELECT * +FROM ( + WITH RECURSIVE deps (classid, objid, objsubid, refclassid, refobjid, refobjsubid) AS ( + SELECT classid, objid, objsubid, + refclassid, refobjid, refobjsubid + FROM pg_depend + WHERE refclassid = 'pg_class'::regclass AND + refobjid = 'create_property_graph_tests.gt'::regclass + UNION ALL + SELECT d.classid, d.objid, d.objsubid, + d.refclassid, d.refobjid, d.refobjsubid + FROM pg_depend d + JOIN deps dp ON d.refclassid = dp.classid AND d.refobjid = dp.objid AND d.refobjsubid = dp.objsubid + ) + SELECT pg_describe_object(classid, objid, objsubid) as obj, + pg_identify_object(classid, objid, objsubid) as ident, + pg_identify_object_as_address(classid, objid, objsubid) as addr + FROM deps +) s +ORDER BY obj COLLATE "C", ident::text COLLATE "C"; + \a\t SELECT pg_get_propgraphdef('g2'::regclass); SELECT pg_get_propgraphdef('g3'::regclass); diff --git a/src/test/regress/sql/event_trigger.sql b/src/test/regress/sql/event_trigger.sql index 32e9bb58c5e..271f443378b 100644 --- a/src/test/regress/sql/event_trigger.sql +++ b/src/test/regress/sql/event_trigger.sql @@ -143,6 +143,19 @@ create user mapping for regress_evt_user server useless_server; alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +CREATE TABLE t2x (i int PRIMARY KEY, j text); + +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); + +DROP PROPERTY GRAPH gx; +DROP TABLE t1x, t2x; + -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; diff --git a/src/test/regress/sql/object_address.sql b/src/test/regress/sql/object_address.sql index 1bbe9457c1c..27109d421c7 100644 --- a/src/test/regress/sql/object_address.sql +++ b/src/test/regress/sql/object_address.sql @@ -67,7 +67,9 @@ DECLARE BEGIN FOR objtype IN VALUES ('toast table'), ('index column'), ('sequence column'), ('toast table column'), ('view column'), ('materialized view column'), - ('property graph element'), ('property graph label'), ('property graph property') + ('property graph element'), ('property graph element label'), + ('property graph label'), ('property graph label property'), + ('property graph property') LOOP BEGIN PERFORM pg_get_object_address(objtype, '{one}', '{}'); @@ -282,7 +284,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace -- 2.34.1 --R84XrR4Hgw0dH3Ec-- ^ permalink raw reply [nested|flat] 2390+ messages in thread
end of thread, other threads:[~2026-04-23 09:27 UTC | newest] Thread overview: 2390+ messages (download: mbox mbox.gz follow: Atom feed) -- links below jump to the message on this page -- 2023-06-26 08:05 [PATCH v2 1/7] Row pattern recognition patch for raw parser. Tatsuo Ishii <[email protected]> 2024-03-04 05:26 Some shared memory chunks are allocated even if related processes won't start Hayato Kuroda (Fujitsu) <[email protected]> 2024-03-04 05:33 ` Re: Some shared memory chunks are allocated even if related processes won't start Tom Lane <[email protected]> 2024-03-04 06:10 ` RE: Some shared memory chunks are allocated even if related processes won't start Hayato Kuroda (Fujitsu) <[email protected]> 2024-03-04 08:09 ` Re: Some shared memory chunks are allocated even if related processes won't start Alvaro Herrera <[email protected]> 2024-03-04 09:50 ` RE: Some shared memory chunks are allocated even if related processes won't start Hayato Kuroda (Fujitsu) <[email protected]> 2024-03-04 11:52 ` Re: Some shared memory chunks are allocated even if related processes won't start 'Alvaro Herrera' <[email protected]> 2024-03-04 13:11 ` RE: Some shared memory chunks are allocated even if related processes won't start Hayato Kuroda (Fujitsu) <[email protected]> 2024-03-04 13:50 ` Re: Some shared memory chunks are allocated even if related processes won't start 'Alvaro Herrera' <[email protected]> 2024-03-05 02:00 ` RE: Some shared memory chunks are allocated even if related processes won't start Hayato Kuroda (Fujitsu) <[email protected]> 2024-03-05 07:34 ` Re: Some shared memory chunks are allocated even if related processes won't start 'Alvaro Herrera' <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-23 09:27 [PATCH v3] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-23 09:27 [PATCH v2] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-23 09:27 [PATCH v2] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-23 09:27 [PATCH v3] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-23 09:27 [PATCH v3] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-23 09:27 [PATCH v3] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-23 09:27 [PATCH v2] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-23 09:27 [PATCH v3] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-23 09:27 [PATCH v3] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-23 09:27 [PATCH v3] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-23 09:27 [PATCH v2] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-23 09:27 [PATCH v3] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-23 09:27 [PATCH 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 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 v3] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-23 09:27 [PATCH v2] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-23 09:27 [PATCH v2] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-23 09:27 [PATCH v2] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-23 09:27 [PATCH v3] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-23 09:27 [PATCH v2] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-23 09:27 [PATCH v3] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-23 09:27 [PATCH v3] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-23 09:27 [PATCH v2] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-23 09:27 [PATCH 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 v3] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-23 09:27 [PATCH v2] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-23 09:27 [PATCH v3] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-23 09:27 [PATCH v3] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-23 09:27 [PATCH v2] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-23 09:27 [PATCH v3] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-23 09:27 [PATCH v3] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-23 09:27 [PATCH v2] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-23 09:27 [PATCH v2] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-23 09:27 [PATCH v2] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-23 09:27 [PATCH v3] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-23 09:27 [PATCH 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 v2] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-23 09:27 [PATCH v3] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-23 09:27 [PATCH v3] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-23 09:27 [PATCH v2] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-23 09:27 [PATCH v2] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-23 09:27 [PATCH v2] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-23 09:27 [PATCH v3] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-23 09:27 [PATCH v2] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-23 09:27 [PATCH v3] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-23 09:27 [PATCH v3] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-23 09:27 [PATCH v2] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-23 09:27 [PATCH v3] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-23 09:27 [PATCH v3] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-23 09:27 [PATCH v3] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-23 09:27 [PATCH v2] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-23 09:27 [PATCH v3] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-23 09:27 [PATCH v2] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-23 09:27 [PATCH v3] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-23 09:27 [PATCH v2] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-23 09:27 [PATCH v2] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-23 09:27 [PATCH 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 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 v2] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-23 09:27 [PATCH v3] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-23 09:27 [PATCH v3] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-23 09:27 [PATCH v3] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-23 09:27 [PATCH v3] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-23 09:27 [PATCH v3] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-23 09:27 [PATCH v3] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-23 09:27 [PATCH v2] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-23 09:27 [PATCH v3] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-23 09:27 [PATCH v3] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-23 09:27 [PATCH v3] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-23 09:27 [PATCH v2] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-23 09:27 [PATCH v2] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-23 09:27 [PATCH v2] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-23 09:27 [PATCH v2] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-23 09:27 [PATCH v2] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-23 09:27 [PATCH v3] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-23 09:27 [PATCH v2] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-23 09:27 [PATCH v2] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-23 09:27 [PATCH v3] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-23 09:27 [PATCH v2] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-23 09:27 [PATCH v3] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-23 09:27 [PATCH v2] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-23 09:27 [PATCH v3] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-23 09:27 [PATCH v2] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-23 09:27 [PATCH v2] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-23 09:27 [PATCH v2] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-23 09:27 [PATCH v2] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-23 09:27 [PATCH v2] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-23 09:27 [PATCH v3] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-23 09:27 [PATCH v3] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-23 09:27 [PATCH v2] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-23 09:27 [PATCH v3] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-23 09:27 [PATCH v3] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-23 09:27 [PATCH v2] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-23 09:27 [PATCH v2] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-23 09:27 [PATCH v3] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-23 09:27 [PATCH v3] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-23 09:27 [PATCH v2] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-23 09:27 [PATCH v3] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-23 09:27 [PATCH v3] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-23 09:27 [PATCH v3] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-23 09:27 [PATCH v3] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-23 09:27 [PATCH v2] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-23 09:27 [PATCH v2] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-23 09:27 [PATCH v3] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-23 09:27 [PATCH v2] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-23 09:27 [PATCH v2] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-23 09:27 [PATCH v2] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-23 09:27 [PATCH v2] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-23 09:27 [PATCH v2] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-23 09:27 [PATCH v2] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-23 09:27 [PATCH v2] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-23 09:27 [PATCH 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 v2] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-23 09:27 [PATCH v2] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-23 09:27 [PATCH v2] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-23 09:27 [PATCH v3] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-23 09:27 [PATCH v2] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-23 09:27 [PATCH v2] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-23 09:27 [PATCH v3] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-23 09:27 [PATCH v2] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-23 09:27 [PATCH v3] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-23 09:27 [PATCH v2] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-23 09:27 [PATCH v3] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-23 09:27 [PATCH v2] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-23 09:27 [PATCH v3] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-23 09:27 [PATCH v3] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-23 09:27 [PATCH v3] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-23 09:27 [PATCH v2] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-23 09:27 [PATCH v3] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-23 09:27 [PATCH v2] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-23 09:27 [PATCH v2] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-23 09:27 [PATCH v3] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-23 09:27 [PATCH v3] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-23 09:27 [PATCH v2] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-23 09:27 [PATCH v2] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-23 09:27 [PATCH 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 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